Miten voin luoda satunnaisia kokonaislukuja kahden määritetyn muuttujan välillä JavaScriptissä, esimerkiksi x = 4
ja y = 8
tulostaisi minkä tahansa seuraavista: 4, 5, 6, 7, 8
?
Esimerkkejä on Mozilla Developer Network -sivulla:
/**
* 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;
}
Tässä'on logiikka sen takana. Se'on yksinkertainen kolmen sääntö:
Math.random()
palauttaa Luvun
väliltä 0 (mukaan lukien) ja 1 (pois lukien). Meillä on siis tällainen väli:
[0 .................................... 1)
Nyt haluaisimme luvun väliltä min
(mukaan lukien) ja max
(pois lukien):
[0 .................................... 1)
[min .................................. max)
Voimme käyttää Math.random
:ia saadaksemme vastaavan luvun väliltä [min, max]. Mutta ensin meidän pitäisi hieman faktoroida ongelmaa vähentämällä min
toisesta intervallista:
[0 .................................... 1)
[min - min ............................ max - min)
Tämä antaa:
[0 .................................... 1)
[0 .................................... max - min)
Voimme nyt soveltaa Math.random
ja laskea sitten vastaavan. Valitaan satunnaisluku:
Math.random()
|
[0 .................................... 1)
[0 .................................... max - min)
|
x (what we need)
Löytääksemme x
, teemme näin:
x = Math.random() * (max - min);
Älä unohda lisätä min
takaisin, jotta saamme luvun [min, max]-välille:
x = Math.random() * (max - min) + min;
Tämä oli ensimmäinen funktio MDN:stä. Toinen palauttaa kokonaisluvun väliltä min
ja max
, molemmat mukaan lukien.
Kokonaislukujen saamiseksi voit käyttää round
, ceil
tai floor
.
Voit käyttää Math.round(Math.random() * (max - min)) + min
, mutta tämä antaa kuitenkin epätasaisen jakauman. Sekä min
että max
:lla on vain noin puolet mahdollisuudesta heittää:
min...min+0.5...min+1...min+1.5 ... max-0.5....max
└───┬───┘└────────┬───────┘└───── ... ─────┘└───┬──┘ ← Math.round()
min min+1 max
Kun max
jätetään pois intervallista, sillä on vielä pienempi mahdollisuus heittää kuin min
.
Kun Math.floor(Math.random() * (max - min +1))) + min
saat täysin tasaisen jakauman.
min.... min+1... min+2 ... max-1... max.... max+1 (is excluded from interval)
| | | | | |
└───┬───┘└───┬───┘└─── ... ┘└───┬───┘└───┬───┘ ← Math.floor()
min min+1 max-1 max
Et voi käyttää ceil()
ja -1
tuossa yhtälössä, koska max
:lla oli nyt hieman pienempi mahdollisuus heittää, mutta voit heittää myös (ei-toivotun) min-1
tuloksen.
function getRandomizer(bottom, top) {
return function() {
return Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom;
}
}
käyttö:
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.
}
jaottelu:
Palautamme funktion (lainaten funktionaalisesta ohjelmoinnista), joka kutsuttaessa palauttaa satunnaisen kokonaisluvun arvojen bottom
ja top
väliltä, mukaan lukien. Sanomme 'inclusive', koska haluamme sisällyttää sekä bottom että top palautettavien lukujen joukkoon. Näin getRandomizer( 1, 6 )
palauttaa joko 1, 2, 3, 4, 5 tai 6.
(alin on pienempi luku, ylin on suurempi luku).
Math.random() * ( 1 + top - bottom )
Math.random()
palauttaa satunnaisen kaksoisluvun väliltä 0 ja 1, ja jos kerromme sen yhdellä plus ylä- ja alaluvun erotuksella, saamme kaksoisluvun jossain väliltä 0
ja 1+b-a
.
Math.floor( Math.random() * ( 1 + top - bottom ) )
Math.floor
pyöristää luvun lähimpään kokonaislukuun. Nyt meillä on siis kaikki kokonaisluvut väliltä 0
ja top-bottom
. 1 näyttää hämmentävältä, mutta sen on oltava siinä, koska pyöristämme aina alaspäin, joten ylimpään lukuun ei koskaan päästä ilman sitä. Satunnaisen desimaaliluvun, jonka luomme, on oltava välillä 0
- (1+top-bottom)
, jotta voimme pyöristää alaspäin ja saada int:n välillä 0
- top-bottom
.
Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom
Edellisen esimerkin koodi antoi meille kokonaisluvun välillä 0
ja top-bottom
, joten nyt meidän tarvitsee vain lisätä tulokseen bottom
saadaksemme kokonaisluvun välillä bottom
ja top
mukaan lukien. :D
HUOMAUTUS: Jos annat ensin muun kuin kokonaisluvun tai suuremman luvun, saat ei-toivottua käyttäytymistä, mutta ellei kukaan pyydä sitä, en aio syventyä argumentin tarkistuskoodiin, koska se on melko kaukana alkuperäisen kysymyksen tarkoituksesta.
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)));
}
Voit testata tätä toimintoa ja sen muunnelmia tallentamalla alla olevan HTML/JavaScript-tiedoston tiedostoon ja avaamalla sen selaimella. Koodi tuottaa kaavion, joka näyttää miljoonan funktiokutsun jakautumisen. Koodi tallentaa myös ääritapaukset, joten jos funktio tuottaa arvon, joka on suurempi kuin maksimi tai pienempi kuin minimi, tiedät siitä.
<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>