Kaip "JavaScript" kalba generuoti atsitiktinius sveikus skaičius tarp dviejų nurodytų kintamųjų, pvz., x = 4
ir y = 8
, kad išeitų bet kuris iš 4, 5, 6, 7, 8
?
Keletas pavyzdžių pateikta Mozilla Developer Network puslapyje:
/**
* Returns a random number between min (inclusive) and max (exclusive)
*/
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Štai tokia logika. Tai paprasta trijų dalių taisyklė:
Matas.random()` grąžina skaičių nuo 0 (imtinai) iki 1 (išimtinai). Taigi turime tokį intervalą:
[0 .................................... 1)
Dabar norėtume gauti skaičių tarp min
(imtinai) ir max
(išimtinai):
[0 .................................... 1)
[min .................................. max)
Galime naudoti Math.random
, kad gautume atitikmenį intervale [min, max]. Tačiau pirmiausia turėtume šiek tiek sumažinti problemą, atimdami min
iš antrojo intervalo:
[0 .................................... 1)
[min - min ............................ max - min)
Gauname:
[0 .................................... 1)
[0 .................................... max - min)
Dabar galime taikyti Math.random
ir apskaičiuoti atitikmenį. Pasirinkime atsitiktinį skaičių:
Math.random()
|
[0 .................................... 1)
[0 .................................... max - min)
|
x (what we need)
Taigi, norėdami rasti x
, turėtume atlikti šiuos veiksmus:
x = Math.random() * (max - min);
Nepamirškite pridėti min
, kad gautume skaičių intervale [min, max]:
x = Math.random() * (max - min) + min;
Tai buvo pirmoji funkcija iš MDN. Antroji funkcija grąžina sveikąjį skaičių tarp min
ir max
, abu įskaitytinai.
Dabar, norėdami gauti sveikuosius skaičius, galite naudoti round
, ceil
arba floor
.
Galite naudoti Math.round(Math.random() * (max - min)) + min
, tačiau taip gaunamas nelygus pasiskirstymas. Tiek min
, tiek max
turi tik maždaug pusę tikimybės mesti:
min...min+0.5...min+1...min+1.5 ... max-0.5....max
└───┬───┘└────────┬───────┘└───── ... ─────┘└───┬──┘ ← Math.round()
min min+1 max
Iš intervalo išbraukus max
, tikimybė, kad jis kris, yra dar mažesnė nei min
.
Su Math.floor(Math.random() * (max - min +1)) + min
turite visiškai tolygų pasiskirstymą.
min.... min+1... min+2 ... max-1... max.... max+1 (is excluded from interval)
| | | | | |
└───┬───┘└───┬───┘└─── ... ┘└───┬───┘└───┬───┘ ← Math.floor()
min min+1 max-1 max
Šioje lygtyje negalite naudoti ceil()
ir -1
, nes max
dabar turėjo šiek tiek mažesnę tikimybę, bet galite mesti ir (nepageidaujamą) min-1
rezultatą.
function getRandomizer(bottom, top) {
return function() {
return Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom;
}
}
naudojimas:
var rollDie = getRandomizer( 1, 6 );
var results = ""
for ( var i = 0; i<1000; i++ ) {
results += rollDie() + " "; //make a string filled with 1000 random numbers in the range 1-6.
}
suskirstymas:
Iš funkcinio programavimo pasiskolinta funkcija, kurią iškvietus bus grąžinamas atsitiktinis sveikasis skaičius tarp reikšmių bottom
ir top
imtinai. Sakome 'imtinai', nes norime, kad į grąžintinų skaičių intervalą būtų įtrauktos ir apatinė, ir viršutinė reikšmės. Tokiu būdu getRandomizer( 1, 6 )
grąžins 1, 2, 3, 4, 5 arba 6.
(apačia yra mažesnis skaičius, viršus - didesnis skaičius)
Math.random() * ( 1 + top - bottom )
Math.random()
grąžina atsitiktinį dvigubą skaičių tarp 0 ir 1, o jei jį padauginsime iš vieneto ir skirtumo tarp viršutinio
ir apatinio
, gausime dvigubą skaičių kažkur tarp 0
ir 1+b-a
.
Math.floor( Math.random() * ( 1 + top - bottom ) )
Math.floor
suapvalina skaičių iki artimiausio sveikojo skaičiaus. Taigi dabar turime visus sveikuosius skaičius tarp 0
ir viršutinės-apačios
. 1 atrodo painiai, bet jis ten turi būti, nes mes visada apvaliname žemyn, todėl viršutinio skaičiaus be jo niekada nepasieksime. Atsitiktinis dešimtainis skaičius, kurį generuojame, turi būti nuo 0
iki (1+viršutinis-apatinis)
, kad galėtume apvalinti žemyn ir gauti int nuo 0
iki viršutinis-apatinis
.
Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom
Ankstesniame pavyzdyje pateiktame kode gavome sveikąjį skaičių intervale 0
ir viršūnė-apačia
, todėl dabar tereikia prie šio rezultato pridėti apačia
, kad gautume sveikąjį skaičių intervale apačia
ir viršūnė
imtinai :D
PASTABA: Jei pirmiausia perduosite ne sveikojo skaičiaus reikšmę arba didesnį skaičių, gausite nepageidaujamą elgesį, bet jei niekas neprašo, nesiruošiu gilintis į argumentų tikrinimo kodą, nes jis gana toli nuo pradinio klausimo tikslo.
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
Norėdami išbandyti šią funkciją ir jos variantus, išsaugokite toliau pateiktą HTML/JavaScript į failą ir atidarykite naršyklėje. Kodas sukurs grafiką, rodantį milijono funkcijos iškvietimų pasiskirstymą. Kodas taip pat užfiksuos kraštinius atvejus, todėl jei funkcija sukurs didesnę nei maksimali arba mažesnę nei minimali reikšmę, apie tai sužinosite.
<html>
<head>
<script type="text/javascript">
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
var min = -5;
var max = 5;
var array = new Array();
for(var i = 0; i <= (max - min) + 2; i++) {
array.push(0);
}
for(var i = 0; i < 1000000; i++) {
var random = getRandomInt(min, max);
array[random - min + 1]++;
}
var maxSample = 0;
for(var i = 0; i < max - min; i++) {
maxSample = Math.max(maxSample, array[i]);
}
//create a bar graph to show the sample distribution
var maxHeight = 500;
for(var i = 0; i <= (max - min) + 2; i++) {
var sampleHeight = (array[i]/maxSample) * maxHeight;
document.write('<span style="display:inline-block;color:'+(sampleHeight == 0 ? 'black' : 'white')+';background-color:black;height:'+sampleHeight+'px"> [' + (i + min - 1) + ']: '+array[i]+'</span> ');
}
document.write('<hr/>');
</script>
</head>
<body>
</body>
</html>