2015-03-29 47 views
19

Powiedz, czy chcę, aby wygenerować bezstronnej liczbę losową między min i max, zrobiłbym:Jak generować liczby losowe obciążone w kierunku jednej wartości w zakresie?

var rand = function(min, max) { 
    return Math.floor(Math.random() * (max - min + 1)) + min; 
}; 

Ale co, jeśli chcę, aby wygenerować liczbę losową między min i max ale bardziej stronniczy wobec wartości N między min i max do stopnia D? Najlepiej ilustrują to z krzywej prawdopodobieństwa:

enter image description here

+2

http://en.wikipedia.org/wiki/Gaussian_function – SpiderPig

+0

możliwy duplikat [Generowanie liczb losowych w JavaScript w określonym zakresie?] (Http://stackoverflow.com/questions/1527803/generating-random-numbers -in-javascript-in-a-specific-range) – Ryan

+6

@ryan, który nie jest duplikatem, ponieważ jest losowy bez uprzedzeń. OP prosi o stronniczy wynik. – K3N

Odpowiedz

27

Oto jeden sposób:

  • Get liczb losowych w min-max zakresu
  • uzyskać losową wartość znormalizowaną mix
  • Mieszaj losowo z odchyleniem opartym na losowej mieszance

Tj., W pseudo:

 
Variables: 
    min = 0 
    max = 100 
    bias = 67  (N) 
    influence = 1 (D) [0.0, 1.0] 

Formula: 
    rnd = random() x (max - min) + min 
    mix = random() x influence 
    value = rnd x (1 - mix) + bias x mix 

Współczynnik mieszania można zmniejszyć za pomocą współczynnika dodatkowego, aby określić, jak bardzo powinien on wpływać (np. mix * factor gdzie współczynnik to [0, 1]).

Demo

Spowoduje to polaryzację losową zakresu. Górny prążek ma wpływ 1, dolny wpływ 0.75. Bias jest tutaj ustawiony na 2/3 pozycji w zakresie. Dolne pasmo nie ma (celowe) odchylenie dla porównania.

var ctx = document.querySelector("canvas").getContext("2d"); 
 
ctx.fillStyle = "red"; ctx.fillRect(399,0,2,110); // draw bias target 
 
ctx.fillStyle = "rgba(0,0,0,0.07)"; 
 

 
function getRndBias(min, max, bias, influence) { 
 
    var rnd = Math.random() * (max - min) + min, // random in range 
 
     mix = Math.random() * influence;   // random mixer 
 
    return rnd * (1 - mix) + bias * mix;   // mix full range and bias 
 
} 
 

 
// plot biased result 
 
(function loop() { 
 
    for(var i = 0; i < 5; i++) { // just sub-frames (speedier plot) 
 
    ctx.fillRect(getRndBias(0, 600, 400, 1.00), 4, 2, 50); 
 
    ctx.fillRect(getRndBias(0, 600, 400, 0.75), 55, 2, 50); 
 
    ctx.fillRect(Math.random() * 600   ,115, 2, 35); 
 
    } 
 
    requestAnimationFrame(loop); 
 
})();
<canvas width=600></canvas>

+1

Bardzo ładne. Dzięki za wersję demonstracyjną. – c00000fd

+1

@ c00000fd bez problemu! Zapomniałem wspomnieć, że nastawienie może być bardziej wpływowe, przekraczając 1 i ograniczając wynik w miksie. Ale prawdopodobnie już to widzisz. Powodzenia w projekcie! – K3N

2

powiedzieć, kiedy używasz Math.floor(Math.random() * (max - min + 1)) + min;, w rzeczywistości stworzenie dystrybucji jednolity. Aby uzyskać dystrybucję danych na wykresie, potrzebna jest dystrybucja o niezerowym nachyleniu.

Istnieją różne techniki uzyskiwania tego rodzaju dystrybucji. Oto example dystrybucji beta znalezione na stackoverflow.


Oto przykład zestawione z linku:

unif = Math.random() // The original uniform distribution. 

Możemy przenieść je do dystrybucji beta wykonując

beta = sin(unif*pi/2)^2 // The standard beta distribution 

aby uzyskać asymetrii przedstawiono na wykresie,

beta_right = (beta > 0.5) ? 2*beta-1 : 2*(1-beta)-1; 

Możesz zmienić wartość 1 na inną, aby była przekrzywiona na inną wartość.

+1

Dzięki za wyjaśnienie. Chociaż ten link może odpowiedzieć na pytanie, lepiej umieścić tutaj istotne części odpowiedzi i podać odsyłacz do odniesienia. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. –

+1

Dzięki za przypomnienie Lea. – LumiG

2

Dla zabawy, oto wersja, która opiera się na Gaussian function, jak wspomniano w komentarzu SpiderPig do twojego pytania.Funkcja gaussowska jest stosowana do liczby losowej od 1 do 100, gdzie wysokość dzwonu wskazuje, jak blisko końcowa wartość będzie wynosiła N. Zinterpretowałem stopień D, aby określić, jak prawdopodobnie ostateczna wartość ma być bliska N, a więc D odpowiada szerokości dzwonka - im mniejszy jest D, tym mniej prawdopodobne jest odchylenie. Oczywiście, przykład można dalej skalibrować.

(I skopiowane metody płócienną Kena Fyrstenberg do wykazania tej funkcji.)

function randBias(min, max, N, D) { 
 
    var a = 1, 
 
     b = 50, 
 
     c = D; 
 

 
    var influence = Math.floor(Math.random() * (101)), 
 
    x = Math.floor(Math.random() * (max - min + 1)) + min; 
 

 
    return x > N 
 
     ? x + Math.floor(gauss(influence) * (N - x)) 
 
     : x - Math.floor(gauss(influence) * (x - N)); 
 

 
    function gauss(x) { 
 
    return a * Math.exp(-(x - b) * (x - b)/(2 * c * c)); 
 
    } 
 
} 
 

 
var ctx = document.querySelector("canvas").getContext("2d"); 
 
ctx.fillStyle = "red"; 
 
ctx.fillRect(399, 0, 2, 110); 
 
ctx.fillStyle = "rgba(0,0,0,0.07)"; 
 

 
(function loop() { 
 
    for (var i = 0; i < 5; i++) { 
 
    ctx.fillRect(randBias(0, 600, 400, 50), 4, 2, 50); 
 
    ctx.fillRect(randBias(0, 600, 400, 10), 55, 2, 50); 
 
    ctx.fillRect(Math.random() * 600, 115, 2, 35); 
 
    } 
 
    requestAnimationFrame(loop); 
 
})();
<canvas width=600></canvas>

+0

Dzięki. Naprawdę pomogłoby, gdybyś dodał post na żywo, na przykład Ken Fyrstenberg. To naprawdę pomaga zobaczyć skuteczność lub stronniczość PRNG. – c00000fd

+0

@ c00000fd dodane! Myślenie o kształcie i lokalizacji "dzwonka", a także o innych parametrach, może pomóc w ulepszeniu wyników. –

1

Fun: użyć obrazu jako funkcję gęstości. Próbkuj losowe piksele, aż uzyskasz czarny, a następnie weź współrzędną x.

enter image description here

Kod:

getPixels = require("get-pixels"); // npm install get-pixels 

getPixels("distribution.png", function(err, pixels) { 
    var height, r, s, width, x, y; 
    if (err) { 
    return; 
    } 
    width = pixels.shape[0]; 
    height = pixels.shape[1]; 
    while (pixels.get(x, y, 0) !== 0) { 
    r = Math.random(); 
    s = Math.random(); 
    x = Math.floor(r * width); 
    y = Math.floor(s * height); 
    } 
    return console.log(r); 
}); 

Przykład Wydajność:

0.7892316638026386 
0.8595335511490703 
0.5459279934875667 
0.9044852438382804 
0.35129814594984055 
0.5352215224411339 
0.8271261665504426 
0.4871773284394294 
0.8202084102667868 
0.39301465335302055 

Skala do smaku.