Skip to content

Всё для WordPress, веб-разработки — и не только

🎲 Как сгенерировать случайное целое число в диапазоне на JavaScript

🎲 Как сгенерировать случайное целое число в диапазоне на JavaScript

Случайное число нужно везде. ID заказа в интернет-магазине, код сброса пароля, бросок кубика в браузерной игре, выбор победителя розыгрыша. И почти всегда разработчик пишет одну и ту же строчку: Math.random().

Но между «получить случайное дробное от 0 до 1» и «получить случайное целое от 5 до 20», пропасть из трёх операций, в которой новички регулярно ошибаются: Math.floor и Math.ceil, плюс один или не плюс, путаница, которая даёт либо выход за диапазон, либо неравномерное распределение.

Разберём формулу до последней скобки, напишем рабочий генератор на чистом HTML+CSS+JS и заглянем туда, где Math.random() уже не справляется.

💡 Быстрый обзор:

  • Разберите формулу Math.floor(Math.random() * (max - min + 1)) + min, поймите каждую операцию.
  • Узнайте, почему только Math.floor, а не Math.ceil или Math.round, на примерах искажений диапазона.
  • Скопируйте готовый HTML-генератор: два поля, кнопка, вывод результата, чистый JS, без фреймворков.
  • Освойте Crypto.getRandomValues, когда Math.random не годится и нужна криптостойкая альтернатива.

Как работает Math.random()

Math.random(), статический метод встроенного объекта Math. Он не принимает аргументов и возвращает псевдослучайное число с плавающей точкой в диапазоне [0, 1), согласно спецификации MDN. Квадратная скобка у нуля означает «включительно», круглая у единицы, «исключая». То есть вы можете получить, к примеру 0.0, значение около 0.372 или близкое к 0.999, но никогда не получите ровно 1.0.

Распределение, приблизительно равномерное. Реализация зашита в движок (V8, SpiderMonkey, JavaScriptCore), и конкретный алгоритм (обычно xorshift128+) разработчик не выбирает и не сбрасывает, сид задаётся движком при старте.

Сам по себе Math.random() для прикладных задач бесполезен. Играм нужны целые числа, лотереям, целые в диапазоне, криптографии, криптостойкая энтропия, которой у Math.random() нет. Поэтому поверх него всегда наворачивают формулу приведения к диапазону.

Формула: случайное целое в диапазоне [min, max]

Базовая формула, которая покрывает подавляющее большинство случаев в веб-разработке:

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

Разберём на учебном примере с min = 5 и max = 10, опираясь на документацию Math.random:

  • Допустим, Math.random() вернул значение R в диапазоне [0, 1).
  • max - min + 1 = 10 - 5 + 1 = 6, количество возможных целых исходов: 5, 6, 7, 8, 9, 10.
  • R * 6, масштабировали случайное дробное на ширину диапазона.
  • Math.floor(R * 6), отбросили дробную часть вниз. Теперь у нас индекс от 0 до 5.
  • индекс + min, сдвинули на min. Готово: случайное целое от 5 до 10 включительно.

Та же формула в однострочнике:

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

Почему Math.floor, а не Math.ceil или Math.round

Выбор метода округления критически влияет на распределение. Покажем на учебном примере с диапазоном от 1 до 3 (все значения, кроме границ интервалов, расчётные). Подход описан в каноническом ответе на StackOverflow.

С Math.floor и формулой (max - min + 1):

  • Если Math.random() попал в первую треть диапазона [0, 1): умножение на 3 даст значение от 0 до почти 1, Math.floor отбросит дробную часть, получится индекс 0, плюс min, выпадет 1 (ровно треть случаев).
  • Если Math.random() в средней трети: умножение на 3 даст от 1 до почти 2, Math.floor → индекс 1, плюс min2 (ещё треть).
  • Если Math.random() в последней трети: умножение на 3 даст от 2 до почти 3, Math.floor → индекс 2, плюс min3 (последняя треть).

Равномерно.

Что будет с Math.ceil? Math.ceil(Math.random() * 3) даст 1, 2, 3, но у 1 шанс будет ничтожно мал (только при Math.random() ровно 0, что почти не случается). Крайние значения искажены.

Math.round тоже неравномерен: крайние значения получают половинный шанс относительно средних. Поэтому в генерации случайных целых используют исключительно Math.floor.

Полный пример: генератор на HTML, CSS и JavaScript

Рабочая страница, которую можно сохранить как .html и открыть в браузере. Два поля ввода, кнопка, результат на зелёной подложке.

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>

Код намеренно написан на чистом JavaScript, без фреймворков и сборщиков, так его можно скопировать и запустить мгновенно, без npm install. Функция randomInt принимает min и max, возвращает целое включительно по обоим концам. Обработчик кнопки читает значения из полей, валидирует и выводит результат.

Когда Math.random() недостаточно: Crypto.getRandomValues()

Math.random(), псевдослучайный генератор. Его достаточно для игр, анимаций, A/B-тестов и выбора случайного элемента массива. Но для задач, где предсказуемость означает уязвимость, он не годится: токены сброса пароля, ключи API, криптографические nonce, генераторы одноразовых ссылок.

Представьте: вы отправляете пользователю ссылку для сброса пароля с токеном, сгенерированным через Math.random(). Зная сид и алгоритм (а они стандартны для движка), злоумышленник может восстановить последовательность и подобрать токен. Именно поэтому любой код, касающийся безопасности, должен использовать криптостойкий источник случайности.

Для таких сценариев существует Web Crypto API, crypto.getRandomValues(). Он использует криптостойкий источник энтропии операционной системы и заполняет переданный типизированный массив случайными значениями.

Генерация криптостойкого случайного целого в диапазоне:

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}

Здесь используется rejection sampling: функция запрашивает случайное 32-битное значение и отвергает те, что выходят за пределы равномерно делимого диапазона, это исключает смещение (modulo bias), когда одни значения выпадают чаще других.

На практике для большинства веб-приложений хватает Math.random(). Но если вы пишете генератор одноразовых ссылок или кодов подтверждения, берите crypto.getRandomValues().

Видео: генерация случайного числа в JavaScript

Короткая демонстрация от канала dcode, разбор Math.random() и формулы диапазона с живым примером в консоли браузера:

⁉️🤔 Частые вопросы

Включает ли формула Math.floor(Math.random() * (max - min + 1)) + min верхнюю границу?

Да, включает. max - min + 1 даёт количество возможных целых исходов, а Math.floor в комбинации с + min обеспечивает, что max достижим. Например, при min=1, max=3 вы получите 1, 2 или 3, все три значения возможны.

Можно ли использовать Math.ceil вместо Math.floor?

Технически да, но распределение станет неравномерным. При Math.ceil(Math.random() * range) значение min будет выпадать только когда Math.random() вернёт ровно 0, это исчезающе редкое событие. Math.floor даёт каждому целому в диапазоне равный шанс, поэтому в стандартной формуле используют именно его.

Math.random(), это действительно случайное число?

Нет, это псевдослучайное число. Движок JavaScript использует детерминированный алгоритм (обычно xorshift128+), который выдаёт статистически равномерную последовательность, но зная сид, можно предсказать все последующие значения. Для криптографии это неприемлемо, используйте crypto.getRandomValues().

Как сгенерировать случайное число с плавающей точкой в диапазоне?

Уберите Math.floor и + 1: Math.random() * (max - min) + min. Это даст дробное от min включительно до max исключая. Если нужен и верхний конец включительно, замените max - min на max - min + Number.EPSILON, но на практике дробные диапазоны редко требуют включительности верхней границы.

Что быстрее:Math.random() или crypto.getRandomValues()?

Math.random() на порядки быстрее. В бенчмарках на V8 разница достигает стократного и большего разрыва, потому что crypto.getRandomValues() делает системный вызов к /dev/urandom (Linux) или аналогу, а Math.random(), чисто внутрипроцессный PRNG. Для генерации тысяч значений в цикле берите Math.random(), для одного токена безопасности, crypto.getRandomValues().

Случайное число за 30 секунд: что запомнить

Рабочая лошадка, Math.floor(Math.random() * (max - min + 1)) + min. Запомните три правила: всегда Math.floor (не ceil, не round), всегда + 1 в множителе (чтобы max был достижим), всегда + min в конце (чтобы сдвинуть диапазон). Эти три операции покрывают всё, от броска кубика до выбора случайного победителя.

Для кода сброса паролей и токенов, crypto.getRandomValues(). Медленнее, зато криптостойко.

Если нужно просто попробовать, скопируйте HTML-пример выше, сохраните как файл и откройте в браузере. Никаких зависимостей, никаких сборщиков. Работает везде, где есть <script>.