Math.random() возвращает псевдослучайное с равномерной вероятостью в диапазоне от 0 до 1. Включая 0, исключая 1. Такой интервал ещё можно записать как
[0, 1)
— квадратная скобка означает включение числа, круглая – «дырку», исключение.
Math.round() округляет дробные до «ближайшего» целого. От
x - 0.5
(включая) до
x + 0.5
(исключая) округлит до целого
x
. Можно записать так:
[x-0.5, x+0.5)
Функция получения случайного целого в диапазоне от
min
до
max
в описанном варианте старается сгладить вероятности всех целых до равных.
Визуально это представить так: насыпается «дорожка» поваренной соли на диапазон от 0 до 1 – это равномерно распределённые вероятности из
Math.random()
. При этом сама "1" не участвует, но в данном случае это маловажно. Далее умножаем да диапазон, напр. на 4, и с помощью
Math.round()
делим отрезки этой дорожки в кучки для каждого целого. Кучки по краям получатся меньше остальных.
Если случайное
[0, 1)
просто умножить на 4 и округлить
Math.round()
– будет выдавать случайные целые
[0, 4]
(а не до 3). И как неравновероятно!
0 1
[...................)
0 1 2 3 4
00011111222223333344o
Из-за того, что
Math.round()
разбивает пополам расстояние между двумя целыми, получится не 4 а 5 кучек. При чём в крайние, 0 и 4, попадёт всего по пол-интервала. Их вероятность будет 1/2 от полноценных вероятностей для 1, 2 и 3.
Поэтому, в данной реализации генерируют от
min-0.5
до
max+0.5
, чтобы после
Math.round()
вероятности всех целых были одинаковы.
P. S. за эту размазанность
Math.round()
можно недолюбливать и вместо него округлять вниз,
Math.floor() – так случайное целое, как в вашем вопросе, можно получить проще
const rand = (min, max) => min + Math.floor(Math.random() * (max - min + 1));
alert( rand(1, 3) );
Кстати, в программировании часто предпочитают иметь дело с интервалами
[ .. )
– включающими начало, но исключающими конец. Например,
randomInteger(min, max)
никогда бы не вернула
max
. А это задание вышло такое себе, нетрадиционное, у них )