Skip to content

Kaikki WordPressistä, web-kehityksestä — ja paljon muuta

🎲 Kuinka luoda satunnainen kokonaisluku tietyllä välillä JavaScriptillä

🎲 Kuinka luoda satunnainen kokonaisluku tietyllä välillä JavaScriptillä

Satunnaislukuja tarvitaan kaikkialla. Tilausnumerot verkkokaupoissa, salasanan palautuskoodit, nopanheitot selainpeleissä, arvonnan voittajan valinta. Ja lähes aina kehittäjät kirjoittavat saman rivin: Math.random().

Mutta "satunnainen desimaaliluku 0:sta 1:een" ja "satunnainen kokonaisluku 5:stä 20:een" välillä on kolmen operaation kuilu, jossa aloittelijat tekevät säännöllisesti virheitä: Math.floor ja Math.ceil, plus yksi vai ei plussaa, hämmennystä, joka johtaa joko alueen ylivuotoon tai epätasaiseen jakaumaan.

Puretaan kaava viimeistä sulkua myöten, kirjoitetaan toimiva generaattori puhtaalla HTML+CSS+JS:llä ja katsotaan, missä Math.random() jää vajaaksi.

💡 Pikakatsaus:

  • Pura kaava Math.floor(Math.random() * (max - min + 1)) + min, ymmärrä jokainen operaatio.
  • Opi, miksi vain Math.floor toimii, ei Math.ceil tai Math.round, esimerkkeinä alueen vääristymät.
  • Kopioi valmis HTML-generaattori: kaksi kenttää, painike, tulosteen näyttö, puhdas JS, ei frameworkeja.
  • Hallitse Crypto.getRandomValues, kun Math.random ei sovellu ja tarvitset kryptografisesti turvallisen vaihtoehdon.

Miten Math.random() toimii

Math.random() on sisäänrakennetun Math-olion staattinen metodi. Se ei ota argumentteja ja palauttaa pseudo-satunnaisen liukuluvun väliltä [0, 1) MDN-määrittelyn mukaisesti. Hakasulje nollan kohdalla tarkoittaa "sisältäen", kaarisulje ykkösen kohdalla "pois lukien". Voit siis saada 0.0, arvon noin 0.372 tai jotain lähellä 0.999, mutta et koskaan tarkalleen 1.0.

Jakauma on likimain tasainen. Toteutus on sisäänrakennettu moottoriin (V8, SpiderMonkey, JavaScriptCore), eikä kehittäjä voi valita tai nollata tiettyä algoritmia (yleensä xorshift128+); siemenen asettaa moottori käynnistyksen yhteydessä.

Sellaisenaan Math.random() on hyödytön käytännön tehtäviin. Pelit tarvitsevat kokonaislukuja, arpajaiset kokonaislukuja tietyltä väliltä, kryptografia tarvitsee kryptografisesti turvallista entropiaa, jota Math.random() ei tarjoa. Siksi sen ympärille kiedotaan aina alueen muunnoskaava.

Kaava: satunnainen kokonaisluku välillä [min, max]

Peruskaava, joka kattaa valtaosan tapauksista web-kehityksessä:

1function randomInt(min, max) {
2 return Math.floor(Math.random() * (max - min + 1)) + min;
3}

Puretaan se oppimisesimerkillä, jossa min = 5 ja max = 10, perustuen Math.random-dokumentaatioon:

  • Oletetaan, että Math.random() palautti arvon R väliltä [0, 1).
  • max - min + 1 = 10 - 5 + 1 = 6, mahdollisten kokonaislukutulosten määrä: 5, 6, 7, 8, 9, 10.
  • R * 6 skaalasi satunnaisen desimaalin alueen leveyteen.
  • Math.floor(R * 6) pyöristi alaspäin hylkäämällä desimaaliosan. Nyt meillä on indeksi 0:sta 5:een.
  • index + min siirsi min:n verran. Valmis: satunnainen kokonaisluku 5:stä 10:een, molemmat mukaan lukien.

Sama kaava yksirivisenä:

1const roll = Math.floor(Math.random() * (max - min + 1)) + min;

Miksi Math.floor, ei Math.ceil tai Math.round

Pyöristysmenetelmän valinta vaikuttaa kriittisesti jakaumaan. Havainnollistetaan oppimisesimerkillä käyttäen väliä 1:stä 3:een (kaikki arvot paitsi välin rajat on laskettu). Lähestymistapa on kuvattu kanonisessa StackOverflow-vastauksessa.

Käytettäessä Math.floor ja kaavaa (max - min + 1):

  • Jos Math.random() osuu välin [0, 1) ensimmäiseen kolmannekseen: kertominen 3:lla antaa arvon 0:sta lähes 1:een, Math.floor hylkää desimaaliosan, tuottaen indeksin 0, plus min antaa 1 (tasan yksi kolmasosa tapauksista).
  • Jos Math.random() on keskimmäisessä kolmanneksessa: kertominen 3:lla antaa 1:stä lähes 2:een, Math.floor → indeksi 1, plus min2 (toinen kolmasosa).
  • Jos Math.random() on viimeisessä kolmanneksessa: kertominen 3:lla antaa 2:sta lähes 3:een, Math.floor → indeksi 2, plus min3 (viimeinen kolmasosa).

Tasainen jakauma.

Mitä tapahtuu Math.ceil:llä? Math.ceil(Math.random() * 3) antaa 1, 2, 3, mutta 1:llä on mitätön mahdollisuus (vain kun Math.random() on tasan 0, mitä ei juuri koskaan tapahdu). Reuna-arvot vääristyvät.

Math.round on myös epätasainen: reuna-arvot saavat puolet keskimmäisten arvojen mahdollisuudesta. Siksi satunnaisten kokonaislukujen generointi käyttää yksinomaan Math.floor.

Täydellinen esimerkki: generaattori HTML:llä, CSS:llä ja JavaScriptillä

Toimiva sivu, jonka voit tallentaa .html-päätteellä ja avata selaimessa. Kaksi syötekenttää, painike, tulos vihreällä taustalla.

1<!DOCTYPE html>
2<html lang="ru">
3<head>
4 <meta charset="UTF-8">
5 <title>Генератор случайных чисел</title>
6 <style>
7 body {
8 font-family: system-ui, sans-serif;
9 max-width: 400px;
10 margin: 50px auto;
11 padding: 0 16px;
12 }
13 label {
14 display: block;
15 margin-top: 12px;
16 font-weight: 600;
17 }
18 input {
19 width: 100%;
20 padding: 8px;
21 margin-top: 4px;
22 font-size: 16px;
23 box-sizing: border-box;
24 }
25 button {
26 margin-top: 16px;
27 padding: 10px 24px;
28 font-size: 16px;
29 cursor: pointer;
30 }
31 .result {
32 margin-top: 20px;
33 font-size: 24px;
34 font-weight: 700;
35 color: #2e7d32;
36 }
37 </style>
38</head>
39<body>
40
41 <h1>Случайное число в диапазоне</h1>
42
43 <label for="minInput">От:</label>
44 <input type="number" id="minInput" value="1">
45
46 <label for="maxInput">До:</label>
47 <input type="number" id="maxInput" value="100">
48
49 <button id="generateBtn">Сгенерировать</button>
50
51 <div class="result" id="resultDisplay"></div>
52
53 <script>
54 function randomInt(min, max) {
55 return Math.floor(Math.random() * (max - min + 1)) + min;
56 }
57
58 const minInput = document.getElementById('minInput');
59 const maxInput = document.getElementById('maxInput');
60 const generateBtn = document.getElementById('generateBtn');
61 const resultDisplay = document.getElementById('resultDisplay');
62
63 generateBtn.addEventListener('click', () => {
64 const min = parseInt(minInput.value, 10);
65 const max = parseInt(maxInput.value, 10);
66
67 if (isNaN(min) || isNaN(max)) {
68 resultDisplay.textContent = 'Введите оба числа';
69 return;
70 }
71 if (min > max) {
72 resultDisplay.textContent = '«От» не может быть больше «До»';
73 return;
74 }
75
76 const result = randomInt(min, max);
77 resultDisplay.textContent = `Результат: ${result}`;
78 });
79 </script>
80
81</body>
82</html>

Koodi on tarkoituksella kirjoitettu puhtaalla JavaScriptillä, ilman frameworkeja tai paketointityökaluja, jotta sen voi kopioida ja ajaa heti ilman npm install -komentoa. randomInt-funktio ottaa min ja max, palauttaen kokonaisluvun, joka sisältää molemmat päät. Painikkeen käsittelijä lukee arvot kentistä, validoi ne ja näyttää tuloksen.

Kun Math.random() ei riitä: Crypto.getRandomValues()

Math.random() on pseudo-satunnaisgeneraattori. Se riittää peleihin, animaatioihin, A/B-testeihin ja satunnaisen taulukon alkion valintaan. Mutta tehtäviin, joissa ennustettavuus tarkoittaa haavoittuvuutta, se ei sovellu: salasanan palautustunnisteet, API-avaimet, kryptografiset noncet, kertakäyttöisten linkkien generaattorit.

Kuvittele: lähetät käyttäjälle salasanan palautuslinkin, jonka tunniste on generoitu Math.random():lla. Kun siemen ja algoritmi tunnetaan (ne ovat moottorille vakioita), hyökkääjä voi rekonstruoida sekvenssin ja arvata tunnisteen. Juuri siksi minkä tahansa tietoturvaan liittyvän koodin on käytettävä kryptografisesti turvallista satunnaisuuslähdettä.

Tällaisia skenaarioita varten on olemassa Web Crypto API: crypto.getRandomValues(). Se käyttää käyttöjärjestelmän kryptografisesti turvallista entropialähdettä ja täyttää annetun tyypitetyn taulukon satunnaisarvoilla.

Kryptografisesti turvallisen satunnaisen kokonaisluvun generointi tietyltä väliltä:

1function secureRandomInt(min, max) {
2 const range = max - min + 1;
3 const maxSafeVal = Math.floor(256 ** 4 / range) * range;
4 const buffer = new Uint32Array(1);
5
6 do {
7 crypto.getRandomValues(buffer);
8 } while (buffer[0] >= maxSafeVal);
9
10 return min + (buffer[0] % range);
11}

Tämä käyttää hylkäysotantaa: funktio pyytää satunnaista 32-bittistä arvoa ja hylkää ne, jotka osuvat tasaisesti jaollisen alueen ulkopuolelle. Tämä eliminoi modulo-harhan, jossa jotkin arvot esiintyvät useammin kuin toiset.

Käytännössä Math.random() riittää useimpiin verkkosovelluksiin. Mutta jos kirjoitat generaattoria kertakäyttölinkeille tai vahvistuskoodeille, käytä crypto.getRandomValues().

Video: satunnaisluvun generointi JavaScriptissä

Lyhyt demonstraatio dcode-kanavalta, jossa puretaan Math.random() ja aluekaava live-esimerkillä selaimen konsolissa:

⁉️🤔 Usein kysytyt kysymykset

Sisältääkö kaava Math.floor(Math.random() * (max - min + 1)) + min ylärajan?

Kyllä sisältää. max - min + 1 antaa mahdollisten kokonaislukutulosten määrän, ja Math.floor yhdistettynä + min varmistaa, että max on saavutettavissa. Esimerkiksi arvoilla min=1, max=3 saat 1, 2 tai 3; kaikki kolme arvoa ovat mahdollisia.

Voiko Math.ceil käyttää Math.floor sijasta?

Teknisesti kyllä, mutta jakaumasta tulee epätasainen. Kun käytetään Math.ceil(Math.random() * range), arvo min esiintyy vain, kun Math.random() palauttaa tasan 0, mikä on äärimmäisen harvinainen tapahtuma. Math.floor antaa jokaiselle välin kokonaisluvulle yhtä suuren mahdollisuuden, minkä vuoksi vakiokaava käyttää sitä.

Onko Math.random() todella satunnainen luku?

Ei, se on pseudo-satunnainen luku. JavaScript-moottori käyttää determinististä algoritmia (yleensä xorshift128+), joka tuottaa tilastollisesti tasaisen sekvenssin, mutta siemenen tunteminen mahdollistaa kaikkien myöhempien arvojen ennustamisen. Kryptografiaan tämä ei kelpaa; käytä crypto.getRandomValues().

Miten generoidaan satunnainen liukuluku tietyltä väliltä?

Poista Math.floor ja + 1: Math.random() * (max - min) + min. Tämä antaa desimaaliluvun min:stä (mukaan lukien) max:iin (pois lukien). Jos tarvitset myös ylärajan mukaan, korvaa max - min lausekkeella max - min + Number.EPSILON, mutta käytännössä desimaalivälit vaativat harvoin ylärajan sisällyttämistä.

Kumpi on nopeampi: Math.random() vai crypto.getRandomValues()?

Math.random() on kertaluokkia nopeampi. V8:n benchmarkeissa ero on satakertainen tai enemmän, koska crypto.getRandomValues() tekee järjestelmäkutsun /dev/urandom (Linux) tai vastaavaan, kun taas Math.random() on puhtaasti prosessin sisäinen PRNG. Tuhansien arvojen generointiin silmukassa käytä Math.random(); yksittäiselle tietoturvatunnisteelle käytä crypto.getRandomValues().

Satunnaisluku 30 sekunnissa: mitä muistaa

Työjuhta on Math.floor(Math.random() * (max - min + 1)) + min. Muista kolme sääntöä: aina Math.floor (ei ceil, ei round), aina + 1 kertoimessa (jotta max on saavutettavissa), aina + min lopussa (alueen siirtämiseksi). Nämä kolme operaatiota kattavat kaiken nopanheitoista satunnaisen voittajan valintaan.

Salasanan palautuskoodeihin ja tunnisteisiin käytä crypto.getRandomValues(). Hitaampi, mutta kryptografisesti turvallinen.

Jos haluat vain kokeilla, kopioi yllä oleva HTML-esimerkki, tallenna se tiedostona ja avaa selaimessa. Ei riippuvuuksia, ei paketointityökaluja. Toimii missä tahansa, missä on <script>.