Skip to content

Alt om WordPress, webutvikling — og mer til

🎲 Hvordan generere et tilfeldig heltall i et intervall med JavaScript

🎲 Hvordan generere et tilfeldig heltall i et intervall med JavaScript

Tilfeldige tall trengs overalt. Ordre-ID-er i nettbutikker, tilbakestillingskoder for passord, terningkast i nettleserspill, trekning av vinnere i konkurranser. Og nesten alltid skriver utviklere den samme linjen: Math.random().

Men mellom «få et tilfeldig desimaltall fra 0 til 1» og «få et tilfeldig heltall fra 5 til 20» ligger en kløft på tre operasjoner der nybegynnere jevnlig gjør feil: Math.floor og Math.ceil, pluss én eller ikke pluss, forvirring som fører til enten områdeoverskridelse eller ujevn fordeling.

La oss bryte ned formelen til siste parentes, skrive en fungerende generator i ren HTML+CSS+JS, og se på hvor Math.random() kommer til kort.

💡 Rask oversikt:

  • Bryt ned formelen Math.floor(Math.random() * (max - min + 1)) + min, forstå hver operasjon.
  • Lær hvorfor bare Math.floor fungerer, ikke Math.ceil eller Math.round, med eksempler på områdeforvrengninger.
  • Kopier en ferdig HTML-generator: to felt, en knapp, resultatvisning, ren JS, ingen rammeverk.
  • Mestre Crypto.getRandomValues når Math.random ikke er egnet og du trenger et kryptografisk sikkert alternativ.

Slik fungerer Math.random()

Math.random() er en statisk metode i det innebygde Math-objektet. Den tar ingen argumenter og returnerer et pseudotilfeldig flyttall i området [0, 1), ifølge MDN-spesifikasjonen. Hakeparentesen ved null betyr «inklusive», rundparentesen ved én betyr «eksklusive». Så du kan få 0.0, en verdi rundt 0.372, eller noe nær 0.999, men du får aldri nøyaktig 1.0.

Fordelingen er tilnærmet uniform. Implementasjonen er innebygd i motoren (V8, SpiderMonkey, JavaScriptCore), og utvikleren kan ikke velge eller tilbakestille den spesifikke algoritmen (vanligvis xorshift128+); frøet settes av motoren ved oppstart.

I seg selv er Math.random() ubrukelig for praktiske oppgaver. Spill trenger heltall, lotterier trenger heltall innenfor et område, kryptografi trenger kryptografisk sikker entropi som Math.random() mangler. Derfor pakkes alltid en områdekonverteringsformel rundt den.

Formelen: tilfeldig heltall i området [min, max]

Grunnformelen som dekker de aller fleste tilfeller innen webutvikling:

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

La oss bryte den ned med et læringseksempel der min = 5 og max = 10, basert på Math.random-dokumentasjonen:

  • Anta at Math.random() returnerte en verdi R i området [0, 1).
  • max - min + 1 = 10 - 5 + 1 = 6, antallet mulige heltallsutfall: 5, 6, 7, 8, 9, 10.
  • R * 6 skalerte det tilfeldige desimaltallet til bredden av området.
  • Math.floor(R * 6) rundet ned ved å forkaste desimaldelen. Nå har vi en indeks fra 0 til 5.
  • index + min forskjøv med min. Ferdig: et tilfeldig heltall fra og med 5 til og med 10.

Samme formel som en énlinjer:

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

Hvorfor Math.floor, ikke Math.ceil eller Math.round

Valget av avrundingsmetode påvirker fordelingen kritisk. La oss demonstrere med et læringseksempel med området fra 1 til 3 (alle verdier unntatt intervallgrensene er beregnet). Tilnærmingen er beskrevet i det kanoniske StackOverflow-svaret.

Med Math.floor og formelen (max - min + 1):

  • Hvis Math.random() faller i den første tredjedelen av området [0, 1): multiplikasjon med 3 gir en verdi fra 0 til nesten 1, Math.floor forkaster desimaldelen, produserer indeks 0, pluss min gir 1 (nøyaktig en tredjedel av tilfellene).
  • Hvis Math.random() er i den midtre tredjedelen: multiplikasjon med 3 gir fra 1 til nesten 2, Math.floor → indeks 1, pluss min2 (en tredjedel til).
  • Hvis Math.random() er i den siste tredjedelen: multiplikasjon med 3 gir fra 2 til nesten 3, Math.floor → indeks 2, pluss min3 (den siste tredjedelen).

Uniform fordeling.

Hva skjer med Math.ceil? Math.ceil(Math.random() * 3) gir 1, 2, 3, men 1 har en neglisjerbar sjanse (bare når Math.random() er nøyaktig 0, noe som nesten aldri skjer). Kantverdier forvrenges.

Math.round er også ikke-uniform: kantverdier får halvparten av sjansen sammenlignet med midtverdier. Derfor bruker generering av tilfeldige heltall utelukkende Math.floor.

Komplett eksempel: generator i HTML, CSS og JavaScript

En fungerende side du kan lagre som .html og åpne i en nettleser. To inndatafelt, en knapp, resultat på grønn bakgrunn.

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 er bevisst skrevet i ren JavaScript, uten rammeverk eller bundlere, slik at den kan kopieres og kjøres umiddelbart uten npm install. Funksjonen randomInt tar min og max, og returnerer et heltall inklusivt i begge ender. Knappebehandleren leser verdier fra feltene, validerer dem og viser resultatet.

Når Math.random() ikke er nok: Crypto.getRandomValues()

Math.random() er en pseudotilfeldig generator. Den er tilstrekkelig for spill, animasjoner, A/B-tester og valg av et tilfeldig array-element. Men for oppgaver der forutsigbarhet betyr sårbarhet, er den ikke egnet: tilbakestillingstoken for passord, API-nøkler, kryptografiske nonces, generatorer for engangslenker.

Tenk deg: du sender en bruker en lenke for tilbakestilling av passord med et token generert via Math.random(). Ved å kjenne frøet og algoritmen (som er standard for motoren), kan en angriper rekonstruere sekvensen og gjette tokenet. Det er nettopp derfor all sikkerhetsrelatert kode må bruke en kryptografisk sikker kilde til tilfeldighet.

For slike scenarioer finnes Web Crypto API: crypto.getRandomValues(). Den bruker operativsystemets kryptografisk sikre entropikilde og fyller den oppgitte typede arrayen med tilfeldige verdier.

Generering av et kryptografisk sikkert tilfeldig heltall i et område:

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}

Dette bruker avvisningssampling: funksjonen ber om en tilfeldig 32-bits verdi og avviser de som faller utenfor det jevnt delbare området. Dette eliminerer modulo-bias, når noen verdier forekommer oftere enn andre.

I praksis er Math.random() tilstrekkelig for de fleste webapplikasjoner. Men hvis du skriver en generator for engangslenker eller bekreftelseskoder, bruk crypto.getRandomValues().

Video: generering av et tilfeldig tall i JavaScript

En kort demonstrasjon fra dcode-kanalen, som bryter ned Math.random() og områdeformelen med et live-eksempel i nettleserkonsollen:

⁉️🤔 Ofte stilte spørsmål

Inkluderer formelen Math.floor(Math.random() * (max - min + 1)) + min den øvre grensen?

Ja, det gjør den. max - min + 1 gir antallet mulige heltallsutfall, og Math.floor kombinert med + min sikrer at max er oppnåelig. For eksempel, med min=1, max=3 får du 1, 2 eller 3; alle tre verdiene er mulige.

Kan du bruke Math.ceil i stedet for Math.floor?

Teknisk sett ja, men fordelingen blir ikke-uniform. Med Math.ceil(Math.random() * range) vil verdien min bare forekomme når Math.random() returnerer nøyaktig 0, en forsvinnende sjelden hendelse. Math.floor gir hvert heltall i området lik sjanse, og derfor bruker standardformelen den.

Er Math.random() et virkelig tilfeldig tall?

Nei, det er et pseudotilfeldig tall. JavaScript-motoren bruker en deterministisk algoritme (vanligvis xorshift128+) som produserer en statistisk uniform sekvens, men å kjenne frøet tillater forutsigelse av alle påfølgende verdier. For kryptografi er dette uakseptabelt; bruk crypto.getRandomValues().

Hvordan genererer du et tilfeldig flyttall i et område?

Fjern Math.floor og + 1: Math.random() * (max - min) + min. Dette gir et desimaltall fra min inklusivt til max eksklusivt. Hvis du trenger den øvre enden inklusiv også, erstatt max - min med max - min + Number.EPSILON, men i praksis krever desimalområder sjelden inklusivitet for øvre grense.

Hva er raskest: Math.random() eller crypto.getRandomValues()?

Math.random() er størrelsesordener raskere. I V8-benchmarks når forskjellen et hundrefoldig gap eller mer, fordi crypto.getRandomValues() gjør et systemkall til /dev/urandom (Linux) eller tilsvarende, mens Math.random() er en ren PRNG i prosessen. For å generere tusenvis av verdier i en løkke, bruk Math.random(); for et enkelt sikkerhetstoken, bruk crypto.getRandomValues().

Tilfeldig tall på 30 sekunder: hva du bør huske

Arbeidshesten er Math.floor(Math.random() * (max - min + 1)) + min. Husk tre regler: alltid Math.floor (ikke ceil, ikke round), alltid + 1 i multiplikatoren (slik at max er oppnåelig), alltid + min på slutten (for å forskyve området). Disse tre operasjonene dekker alt fra terningkast til å velge en tilfeldig vinner.

For tilbakestillingskoder og token for passord, bruk crypto.getRandomValues(). Tregere, men kryptografisk sikkert.

Hvis du bare vil prøve det ut, kopier HTML-eksempelet ovenfor, lagre det som en fil og åpne det i en nettleser. Ingen avhengigheter, ingen bundlere. Fungerer overalt der det finnes en <script>.