Skip to content

Tout pour WordPress, le développement web — et plus encore

🎲 Comment générer un entier aléatoire dans un intervalle avec JavaScript

🎲 Comment générer un entier aléatoire dans un intervalle avec JavaScript

Des nombres aléatoires, on en a besoin partout. Identifiants de commande dans les boutiques en ligne, codes de réinitialisation de mot de passe, lancers de dés dans les jeux sur navigateur, sélection d’un gagnant pour une tombola. Et presque toujours, les développeurs écrivent la même ligne: Math.random().

Mais entre «obtenir un nombre décimal aléatoire entre 0 et 1» et «obtenir un entier aléatoire entre 5 et 20», il y a un fossé de trois opérations où les débutants se trompent régulièrement: Math.floor et Math.ceil, plus un ou pas plus un, une confusion qui conduit soit à un débordement de l’intervalle, soit à une distribution non uniforme.

Décortiquons la formule jusqu’à la dernière parenthèse, écrivons un générateur fonctionnel en HTML+CSS+JS pur, et voyons où Math.random() montre ses limites.

💡 Aperçu rapide:

  • Décortiquer la formule Math.floor(Math.random() * (max - min + 1)) + min, comprendre chaque opération.
  • Apprendre pourquoi seul Math.floor fonctionne, et non Math.ceil ou Math.round, avec des exemples de distorsion de l’intervalle.
  • Copier un générateur HTML prêt à l’emploi: deux champs, un bouton, l’affichage du résultat, JS pur, sans framework.
  • Maîtriser Crypto.getRandomValues quand Math.random n’est pas adapté et que vous avez besoin d’une alternative cryptographiquement sûre.

Comment fonctionne Math.random()

Math.random() est une méthode statique de l’objet natif Math. Elle ne prend aucun argument et renvoie un nombre à virgule flottante pseudo-aléatoire dans l’intervalle [0, 1), conformément à la spécification MDN. Le crochet au niveau du zéro signifie «inclus», la parenthèse au niveau du un signifie «exclus». Vous pouvez donc obtenir 0.0, une valeur autour de 0.372, ou quelque chose proche de 0.999, mais vous n’obtiendrez jamais exactement 1.0.

La distribution est approximativement uniforme. L’implémentation est intégrée au moteur (V8, SpiderMonkey, JavaScriptCore), et le développeur ne peut ni choisir ni réinitialiser l’algorithme spécifique (généralement xorshift128+); la graine est fixée par le moteur au démarrage.

En elle-même, Math.random() est inutile pour des tâches pratiques. Les jeux ont besoin d’entiers, les loteries ont besoin d’entiers dans un intervalle, la cryptographie a besoin d’une entropie cryptographiquement sûre que Math.random() ne fournit pas. C’est pourquoi on l’enveloppe toujours dans une formule de conversion d’intervalle.

La formule: entier aléatoire dans l’intervalle [min, max]

La formule de base qui couvre la grande majorité des cas en développement web:

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

Décortiquons-la avec un exemple pédagogique où min = 5 et max = 10, en nous appuyant sur la documentation de Math.random:

  • Supposons que Math.random() ait renvoyé une valeur R dans l’intervalle [0, 1).
  • max - min + 1 = 10 - 5 + 1 = 6, le nombre de résultats entiers possibles: 5, 6, 7, 8, 9, 10.
  • R * 6 a mis à l’échelle le nombre décimal aléatoire sur la largeur de l’intervalle.
  • Math.floor(R * 6) a arrondi à l’entier inférieur en supprimant la partie fractionnaire. Nous avons maintenant un indice de 0 à 5.
  • index + min a décalé de min. Terminé: un entier aléatoire de 5 à 10 inclus.

La même formule en une ligne:

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

Pourquoi Math.floor, et non Math.ceil ou Math.round

Le choix de la méthode d’arrondi affecte de manière critique la distribution. Illustrons-le avec un exemple pédagogique utilisant l’intervalle de 1 à 3 (toutes les valeurs sauf les bornes de l’intervalle sont calculées). L’approche est décrite dans la réponse canonique de StackOverflow.

Avec Math.floor et la formule (max - min + 1):

  • Si Math.random() tombe dans le premier tiers de l’intervalle [0, 1): la multiplication par 3 donne une valeur de 0 à presque 1, Math.floor supprime la partie fractionnaire, produisant l’indice 0, plus min donne 1 (exactement un tiers des cas).
  • Si Math.random() est dans le deuxième tiers: la multiplication par 3 donne de 1 à presque 2, Math.floor → indice 1, plus min2 (un autre tiers).
  • Si Math.random() est dans le dernier tiers: la multiplication par 3 donne de 2 à presque 3, Math.floor → indice 2, plus min3 (le dernier tiers).

Distribution uniforme.

Que se passe-t-il avec Math.ceil? Math.ceil(Math.random() * 3) donne 1, 2, 3, mais 1 a une chance négligeable (seulement quand Math.random() est exactement 0, ce qui n’arrive presque jamais). Les valeurs extrêmes sont faussées.

Math.round est également non uniforme: les valeurs extrêmes ont deux fois moins de chances que les valeurs centrales. C’est pourquoi la génération d’entiers aléatoires utilise exclusivement Math.floor.

Exemple complet: générateur en HTML, CSS et JavaScript

Une page fonctionnelle que vous pouvez enregistrer en .html et ouvrir dans un navigateur. Deux champs de saisie, un bouton, le résultat sur fond vert.

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>

Le code est volontairement écrit en JavaScript pur, sans frameworks ni bundlers, afin de pouvoir être copié et exécuté instantanément sans npm install. La fonction randomInt prend min et max, et renvoie un entier inclusif aux deux extrémités. Le gestionnaire du bouton lit les valeurs des champs, les valide et affiche le résultat.

Quand Math.random() ne suffit pas: Crypto.getRandomValues()

Math.random() est un générateur pseudo-aléatoire. Il est suffisant pour les jeux, les animations, les tests A/B et la sélection d’un élément aléatoire dans un tableau. Mais pour les tâches où la prédictibilité signifie une vulnérabilité, il ne convient pas: jetons de réinitialisation de mot de passe, clés d’API, nonces cryptographiques, générateurs de liens à usage unique.

Imaginez: vous envoyez à un utilisateur un lien de réinitialisation de mot de passe avec un jeton généré via Math.random(). Connaissant la graine et l’algorithme (qui sont standards pour le moteur), un attaquant peut reconstruire la séquence et deviner le jeton. C’est exactement pourquoi tout code lié à la sécurité doit utiliser une source d’aléa cryptographiquement sûre.

Pour de tels scénarios, l’API Web Crypto existe: crypto.getRandomValues(). Elle utilise la source d’entropie cryptographiquement sûre du système d’exploitation et remplit le tableau typé fourni avec des valeurs aléatoires.

Générer un entier aléatoire cryptographiquement sûr dans un intervalle:

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}

Ceci utilise l’échantillonnage par rejet: la fonction demande une valeur aléatoire de 32 bits et rejette celles qui tombent en dehors de la plage divisible de manière égale. Cela élimine le biais de modulo, où certaines valeurs apparaissent plus fréquemment que d’autres.

En pratique, Math.random() est suffisant pour la plupart des applications web. Mais si vous écrivez un générateur pour des liens à usage unique ou des codes de confirmation, utilisez crypto.getRandomValues().

Vidéo: générer un nombre aléatoire en JavaScript

Une courte démonstration de la chaîne dcode, qui décortique Math.random() et la formule d’intervalle avec un exemple en direct dans la console du navigateur:

⁉️🤔 Foire aux questions

Est-ce que la formule Math.floor(Math.random() * (max - min + 1)) + min inclut la borne supérieure?

Oui, elle l’inclut. max - min + 1 donne le nombre de résultats entiers possibles, et Math.floor combiné avec + min garantit que max est atteignable. Par exemple, avec min=1, max=3 vous obtenez 1, 2 ou 3; les trois valeurs sont possibles.

Peut-on utiliser Math.ceil au lieu de Math.floor?

Techniquement oui, mais la distribution devient non uniforme. Avec Math.ceil(Math.random() * range), la valeur min ne se produira que lorsque Math.random() renvoie exactement 0, un événement extrêmement rare. Math.floor donne à chaque entier de l’intervalle une chance égale, c’est pourquoi la formule standard l’utilise.

Math.random() est-il vraiment un nombre aléatoire?

Non, c’est un nombre pseudo-aléatoire. Le moteur JavaScript utilise un algorithme déterministe (généralement xorshift128+) qui produit une séquence statistiquement uniforme, mais connaître la graine permet de prédire toutes les valeurs suivantes. Pour la cryptographie, c’est inacceptable; utilisez crypto.getRandomValues().

Comment générer un nombre à virgule flottante aléatoire dans un intervalle?

Supprimez Math.floor et + 1: Math.random() * (max - min) + min. Cela donne un nombre décimal de min inclus à max exclus. Si vous avez aussi besoin d’inclure la borne supérieure, remplacez max - min par max - min + Number.EPSILON, mais en pratique les intervalles décimaux exigent rarement l’inclusion de la borne supérieure.

Qu’est-ce qui est le plus rapide: Math.random() ou crypto.getRandomValues()?

Math.random() est plus rapide de plusieurs ordres de grandeur. Dans les benchmarks V8, la différence atteint un facteur cent ou plus, parce que crypto.getRandomValues() effectue un appel système à /dev/urandom (Linux) ou équivalent, tandis que Math.random() est un PRNG purement interne au processus. Pour générer des milliers de valeurs dans une boucle, utilisez Math.random(); pour un jeton de sécurité unique, utilisez crypto.getRandomValues().

Nombre aléatoire en 30 secondes: ce qu’il faut retenir

La formule de travail, c’est Math.floor(Math.random() * (max - min + 1)) + min. Retenez trois règles: toujours Math.floor (pas ceil, pas round), toujours + 1 dans le multiplicateur (pour que max soit atteignable), toujours + min à la fin (pour décaler l’intervalle). Ces trois opérations couvrent tout, des lancers de dés à la sélection d’un gagnant au hasard.

Pour les codes de réinitialisation de mot de passe et les jetons, utilisez crypto.getRandomValues(). Plus lent, mais cryptographiquement sûr.

Si vous voulez simplement essayer, copiez l’exemple HTML ci-dessus, enregistrez-le en tant que fichier et ouvrez-le dans un navigateur. Aucune dépendance, aucun bundler. Fonctionne partout où il y a une balise <script>.