Генератор случайных целых чисел не выдаёт значение нижней границы диапазона, если оно отрицательное. Как исправить?
Задача: сгенерировать случайное число из диапазона [-15;10] (включительно). То есть -15 и 10 тоже могут выдаваться в качестве случайного значения.
Пишу на Java такой код:
// границы диапазона
int bottomLimit = -15;
int topLimit = 10;
// генерация
int randomNumber = (int) (Math.random() * (topLimit + 1 - bottomLimit) + bottomLimit);
// вывод
System.out.println(randomNumber);
Действительно, randomNumber при каждом вызове принимает значения то -13, то 0, то 9, в общем из заданного диапазона [-15;10].
Проблема: в качестве случайного значения ни разу не выпадает нижняя граница, то есть -15.
Я это проверил в цикле.
// границы диапазона
int bottomLimit = -15;
int topLimit = 10;
boolean isBottomLimit = false;
boolean isTopLimit = false;
/*
* запускаю генератор 100 000 раз
* Если в качестве значения randomNumber хоть раз выпадет значение bottomLimit,
* то isBottomLimit присваиваем true, которое изначально false.
* Аналогично для isTopLimit.
*/
for (int i = 1; i < 100000; i++) {
int randomNumber = (int) (Math.random() * (topLimit + 1 - bottomLimit) + bottomLimit);
System.out.print(randomNumber + " ");
if (randomNumber == bottomLimit) {
isBottomLimit = true;
}
if (randomNumber == topLimit) {
isTopLimit = true;
}
}
System.out.println("\nСгенерировано ли хоть раз -15: " + isBottomLimit); // false
System.out.println("Сгенерировано ли хоть раз 10: " + isTopLimit); // true
В итоге верхняя граница topLimit диапазона хоть раз, но генерируется.
А нижняя bottomLimit, какое большое бы число проверок не проводилось, не генерируется.
Что изменить в коде, чтобы и нижняя граница тоже «участвовала» в качестве значения случайного числа из диапазона?
P. S. Кстати, если нижняя граница — не отрицательное число, то рандомное число может спокойно принять, как значение и нижней границы диапазона, так и верхней.
int bottomLimit = 5; // нижняя граница диапазона — не отрицательное число
int topLimit = 10;
boolean isBottomLimit = false;
boolean isTopLimit = false;
for (int i = 1; i < 100000; i++) {
int randomNumber = (int) (Math.random() * (topLimit + 1 - bottomLimit) + bottomLimit);
System.out.print(randomNumber + " ");
if (randomNumber == bottomLimit) {
isBottomLimit = true;
}
if (randomNumber == topLimit) {
isTopLimit = true;
}
}
System.out.println("\nСгенерировано ли хоть раз 5: " + isBottomLimit); // true
System.out.println("Сгенерировано ли хоть раз 10: " + isTopLimit); // true
Ответы (2 шт):
Нашёл решение. Нужно в формулу генерации случайного числа вставить не значение нижней границы, а значение нижней границы, уменьшенной на единицу. Причём это нужно делать только тогда, когда нижняя граница отрицательная.
// Границы диапазона [-15;10] (оба включительно)
int bottomLimit = -15;
int topLimit = 10;
boolean isBottomLimit = false;
boolean isTopLimit = false;
/*
* Если нижняя граница диапазона меньше нуля,
* уменьшаем нижнюю границу на единицу,
* иначе оставляем значение нижней границы как есть
*/
int editedBottomLimit = bottomLimit < 0 ? bottomLimit - 1 : bottomLimit;
/*
* При 100 000 проверок хоть раз в качестве случайного числа
* сгенерируется и нижняя граница, и верхняя
*/
for (int i = 1; i < 100000; i++) {
int randomNumber = (int) (Math.random() * (topLimit + 1 - editedBottomLimit) + editedBottomLimit);
System.out.print(randomNumber + " ");
if (randomNumber == bottomLimit) {
isBottomLimit = true;
}
if (randomNumber == topLimit) {
isTopLimit = true;
}
}
System.out.println("\nСгенерировано ли хоть раз " + bottomLimit + ": " + isBottomLimit); // true
System.out.println("Сгенерировано ли хоть раз " + topLimit + ": " + isTopLimit); // true
Ваш генератор псевдослучайных чисел выдает значение 0 в 2 раза чаще, чем остальные значения, это нехорошо.
Если вы хотите генерировать целочисленные значения, то воспользуйтесь целочисленным генератором nextInt() у класса Random (или SecureRandom):
Random random = new SecureRandom();
int randomNumber = random.nextInt(top - bottom + 1) + bottom;
System.out.println(randomNumber);
Для отрезка от -5 до 5 результаты для 1 млн. чисел такие:
-5 => 90984
-4 => 90888
-3 => 91141
-2 => 90878
-1 => 90720
0 => 90855
1 => 91062
2 => 90676
3 => 90659
4 => 91019
5 => 91118