Как правильно использовать Math.random для генерации чисел от 0 до 10000 в JavaScript
Что проверяют
Умеете ли вы аккуратно работать с границами и видите ли подвох в формулировке «от 0 до 10000»: включена ли верхняя граница. Следом часто просят общую функцию для min и max или спрашивают, годится ли Math.random для токенов.
Как отвечать
Math.random() возвращает число с плавающей точкой от 0 включительно до 1 не включая: ноль возможен, единица никогда. Отсюда формулы:
- от 0 до 9999:
Math.floor(Math.random() * 10000), ровно 10000 равновероятных значений; - от 0 до 10000 включительно:
Math.floor(Math.random() * 10001), значений уже 10001; - общий случай:
Math.floor(Math.random() * (max - min + 1)) + minдля целыхminиmaxвключительно.
Стоит сразу сказать, что вы уточнили бы у интервьюера, нужна ли верхняя граница. В этом и суть вопроса.
Дальше про ограничения. Генератор псевдослучайный, в V8 это xorshift128+. Задать seed нельзя, повторить последовательность тоже. Для всего, что связано с безопасностью (токены, коды подтверждения, идентификаторы сессий), нужен crypto.getRandomValues() или crypto.randomUUID(), оба доступны и в браузере, и в Node.js. При этом getRandomValues() отдаёт целые, и привести их к диапазону через % без перекоса не выйдет, если размер диапазона не делит 2^32 нацело.
В тестах случайность подменяют: vi.spyOn(Math, "random").mockReturnValue(0.5) в Vitest или аналог в Jest. Для воспроизводимых тестовых данных берут отдельный генератор с seed из библиотеки.
Где спотыкаются
Берут Math.ceil, чтобы включить 10000. Диапазон сдвигается в 1...10000, а ноль выпадает только при точном нуле от генератора, то есть почти никогда.
Используют Math.round(Math.random() * 10000). Все значения достижимы, но крайние 0 и 10000 выпадают вдвое реже остальных: им достаётся половина интервала округления.
Заменяют Math.floor на | 0 или ~~ ради скорости. Для положительных чисел до 2^31 разницы нет, но на отрицательных результат другой (-1.5 | 0 даёт -1), на больших числах случается переполнение, а выигрыша в современных движках не видно.