Skip to content

Allt om WordPress, webbutveckling — och mer därtill

🎲 Hur man genererar ett slumpmässigt heltal i ett intervall med JavaScript

🎲 Hur man genererar ett slumpmässigt heltal i ett intervall med JavaScript

Slumptal behövs överallt. Order-ID:n i webbutiker, återställningskoder för lösenord, tärningskast i webbläsarspel, dragning av tävlingsvinnare. Och nästan alltid skriver utvecklare samma rad: Math.random().

Men mellan "få ett slumpmässigt decimaltal från 0 till 1" och "få ett slumpmässigt heltal från 5 till 20" ligger en avgrund av tre operationer där nybörjare regelbundet gör misstag: Math.floor och Math.ceil, plus ett eller inte plus ett, förvirring som leder till antingen intervallöverskridning eller ojämn fördelning.

Låt oss bryta ner formeln till sista parentesen, skriva en fungerande generator i ren HTML+CSS+JS och titta på var Math.random() brister.

💡 Snabb översikt:

  • Bryt ner formeln Math.floor(Math.random() * (max - min + 1)) + min, förstå varje operation.
  • Lär dig varför bara Math.floor fungerar, inte Math.ceil eller Math.round, med exempel på intervallförvrängningar.
  • Kopiera en färdig HTML-generator: två fält, en knapp, resultatutskrift, ren JS, inga ramverk.
  • Bemästra Crypto.getRandomValues när Math.random inte är lämpligt och du behöver ett kryptografiskt säkert alternativ.

Hur Math.random() fungerar

Math.random() är en statisk metod på det inbyggda Math-objektet. Den tar inga argument och returnerar ett pseudoslumpmässigt flyttal i intervallet [0, 1), enligt MDN-specifikationen. Hakparentesen vid noll betyder "inklusive", den runda parentesen vid ett betyder "exklusive". Så du kan få 0.0, ett värde runt 0.372 eller något nära 0.999, men du får aldrig exakt 1.0.

Fördelningen är ungefär likformig. Implementationen är inbyggd i motorn (V8, SpiderMonkey, JavaScriptCore), och utvecklaren kan inte välja eller återställa den specifika algoritmen (vanligtvis xorshift128+); fröet sätts av motorn vid uppstart.

I sig själv är Math.random() oanvändbart för praktiska uppgifter. Spel behöver heltal, lotterier behöver heltal inom ett intervall, kryptografi behöver kryptografiskt säker entropi som Math.random() saknar. Därför lindas alltid en intervallomvandlingsformel runt den.

Formeln: slumpmässigt heltal i intervallet [min, max]

Grundformeln som täcker de allra flesta fall inom webbutveckling:

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

Låt oss bryta ner den med ett inlärningsexempel där min = 5 och max = 10, baserat på Math.random-dokumentationen:

  • Anta att Math.random() returnerade ett värde R i intervallet [0, 1).
  • max - min + 1 = 10 - 5 + 1 = 6, antalet möjliga heltalsutfall: 5, 6, 7, 8, 9, 10.
  • R * 6 skalade det slumpmässiga decimaltalet till intervallets bredd.
  • Math.floor(R * 6) avrundade nedåt genom att kasta bort decimaldelen. Nu har vi ett index från 0 till 5.
  • index + min försköt med min. Klart: ett slumpmässigt heltal från 5 till 10 inklusive.

Samma formel som en enradare:

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

Varför Math.floor, inte Math.ceil eller Math.round

Valet av avrundningsmetod påverkar fördelningen avgörande. Låt oss demonstrera med ett inlärningsexempel med intervallet från 1 till 3 (alla värden utom intervallgränser är beräknade). Tillvägagångssättet beskrivs i det kanoniska StackOverflow-svaret.

Med Math.floor och formeln (max - min + 1):

  • Om Math.random() hamnar i den första tredjedelen av intervallet [0, 1): multiplikation med 3 ger ett värde från 0 till nästan 1, Math.floor kastar decimaldelen, vilket ger index 0, plus min ger 1 (exakt en tredjedel av fallen).
  • Om Math.random() är i mellersta tredjedelen: multiplikation med 3 ger från 1 till nästan 2, Math.floor → index 1, plus min2 (ytterligare en tredjedel).
  • Om Math.random() är i sista tredjedelen: multiplikation med 3 ger från 2 till nästan 3, Math.floor → index 2, plus min3 (den sista tredjedelen).

Likformig fördelning.

Vad händer med Math.ceil? Math.ceil(Math.random() * 3) ger 1, 2, 3, men 1 har en försumbar chans (endast när Math.random() är exakt 0, vilket nästan aldrig inträffar). Kantvärden förvrängs.

Math.round är också icke-likformig: kantvärden får halva chansen jämfört med mittenvärden. Det är därför generering av slumpmässiga heltal uteslutande använder Math.floor.

Komplett exempel: generator i HTML, CSS och JavaScript

En fungerande sida du kan spara som .html och öppna i en webbläsare. Två inmatningsfält, en knapp, resultat på grön bakgrund.

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>

Koden är avsiktligt skriven i ren JavaScript, utan ramverk eller paketerare, så att den kan kopieras och köras direkt utan npm install. Funktionen randomInt tar min och max och returnerar ett heltal inklusive i båda ändar. Knapphanteraren läser värden från fälten, validerar dem och visar resultatet.

När Math.random() inte räcker: Crypto.getRandomValues()

Math.random() är en pseudoslumpgenerator. Den räcker för spel, animationer, A/B-tester och att välja ett slumpmässigt arrayelement. Men för uppgifter där förutsägbarhet innebär sårbarhet är den inte lämplig: återställningstoken för lösenord, API-nycklar, kryptografiska nonces, engångslänkgeneratorer.

Föreställ dig: du skickar en användare en länk för lösenordsåterställning med en token genererad via Math.random(). Genom att känna till fröet och algoritmen (som är standard för motorn) kan en angripare rekonstruera sekvensen och gissa token. Det är precis därför all säkerhetsrelaterad kod måste använda en kryptografiskt säker slumpkälla.

För sådana scenarier finns Web Crypto API: crypto.getRandomValues(). Den använder operativsystemets kryptografiskt säkra entropikälla och fyller den tillhandahållna typade arrayen med slumpmässiga värden.

Generera ett kryptografiskt säkert slumpmässigt heltal i ett intervall:

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}

Detta använder rejectionsampling: funktionen begär ett slumpmässigt 32-bitarsvärde och avvisar de som hamnar utanför det jämnt delbara intervallet. Detta eliminerar modulo-bias, när vissa värden förekommer oftare än andra.

I praktiken räcker Math.random() för de flesta webbapplikationer. Men om du skriver en generator för engångslänkar eller bekräftelsekoder, använd crypto.getRandomValues().

Video: generera ett slumpmässigt tal i JavaScript

En kort demonstration från dcode-kanalen, som bryter ner Math.random() och intervallformeln med ett live-exempel i webbläsarkonsolen:

⁉️🤔 Vanliga frågor

Inkluderar formeln Math.floor(Math.random() * (max - min + 1)) + min den övre gränsen?

Ja, det gör den. max - min + 1 ger antalet möjliga heltalsutfall, och Math.floor kombinerat med + min säkerställer att max är nåbart. Till exempel, med min=1, max=3 får du 1, 2 eller 3; alla tre värden är möjliga.

Kan man använda Math.ceil istället för Math.floor?

Tekniskt sett ja, men fördelningen blir icke-likformig. Med Math.ceil(Math.random() * range) kommer värdet min bara att inträffa när Math.random() returnerar exakt 0, en försvinnande sällsynt händelse. Math.floor ger varje heltal i intervallet en lika stor chans, vilket är anledningen till att standardformeln använder den.

Är Math.random() ett verkligt slumpmässigt tal?

Nej, det är ett pseudoslumpmässigt tal. JavaScript-motorn använder en deterministisk algoritm (vanligtvis xorshift128+) som producerar en statistiskt likformig sekvens, men att känna till fröet gör det möjligt att förutsäga alla efterföljande värden. För kryptografi är detta oacceptabelt; använd crypto.getRandomValues().

Hur genererar man ett slumpmässigt flyttal i ett intervall?

Ta bort Math.floor och + 1: Math.random() * (max - min) + min. Detta ger ett decimaltal från min inklusive till max exklusive. Om du behöver den övre änden inklusive också, ersätt max - min med max - min + Number.EPSILON, men i praktiken kräver decimalintervall sällan inklusiv övre gräns.

Vilken är snabbast: Math.random() eller crypto.getRandomValues()?

Math.random() är storleksordningar snabbare. I V8-riktmärken når skillnaden upp till hundra gånger eller mer, eftersom crypto.getRandomValues() gör ett systemanrop till /dev/urandom (Linux) eller motsvarande, medan Math.random() är en rent processintern PRNG. För att generera tusentals värden i en loop, använd Math.random(); för en enstaka säkerhetstoken, använd crypto.getRandomValues().

Slumptal på 30 sekunder: vad du ska komma ihåg

Arbetshästen är Math.floor(Math.random() * (max - min + 1)) + min. Kom ihåg tre regler: alltid Math.floor (inte ceil, inte round), alltid + 1 i multiplikatorn (så att max är nåbart), alltid + min på slutet (för att förskjuta intervallet). Dessa tre operationer täcker allt från tärningskast till att välja en slumpmässig vinnare.

För återställningskoder för lösenord och token, använd crypto.getRandomValues(). Långsammare, men kryptografiskt säkert.

Om du bara vill testa, kopiera HTML-exemplet ovan, spara det som en fil och öppna den i en webbläsare. Inga beroenden, inga paketerare. Fungerar överallt där det finns en <script>.