Как сгенерировать случайное значение int
в определенном диапазоне?
В следующих методах есть ошибки, связанные с целочисленным переполнением:
randomNum = minimum + (int)(Math.random() * maximum);
// Bug: `randomNum` can be bigger than `maximum`.
Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum = minimum + i;
// Bug: `randomNum` can be smaller than `minimum`.
29 ответов
Начиная с Java 7, вы больше не должны использовать
Random
. Для большинства применений Генератор случайных чисел по выбору теперьThreadLocalRandom
.
Для пулов вилочного соединения и параллельных потоки, используйтеSplittableRandom
.
Джошуа Блох. Эффективная Ява. Третье издание.
Начиная с Явы 8
Для пулов соединений fork и параллельных потоков используйте SplittableRandom
, который обычно быстрее, имеет лучшую статистическую независимость и свойства единообразия по сравнению с Random
.
Чтобы сгенерировать случайное int
в диапазоне [0, 1_000]:
int n = new SplittableRandom().nextInt(0, 1_001);
Чтобы сгенерировать случайный массив int[100]
значений в диапазоне [0, 1_000]:
int[] a = new SplittableRandom().ints(100, 0, 1_001).parallel().toArray();
Чтобы вернуть поток случайных значений:
IntStream stream = new SplittableRandom().ints(100, 0, 1_001);
.parallel()
? Мне кажется, что генерация 100 случайных чисел была бы слишком тривиальной, чтобы гарантировать параллелизм.
parallel
). Кстати, для массива из 1_000_000
элементов версия parallel
на моей машине была в 2 раза быстрее по сравнению с последовательной.
Я нашел этот пример Создание случайных чисел:
В этом примере создаются случайные целые числа в определенном диапазоне.
import java.util.Random;
/** Generate random integers in a certain range. */
public final class RandomRange {
public static final void main(String... aArgs){
log("Generating random integers in the range 1..10.");
int START = 1;
int END = 10;
Random random = new Random();
for (int idx = 1; idx <= 10; ++idx){
showRandomInteger(START, END, random);
}
log("Done.");
}
private static void showRandomInteger(int aStart, int aEnd, Random aRandom){
if ( aStart > aEnd ) {
throw new IllegalArgumentException("Start cannot exceed End.");
}
//get the range, casting to long to avoid overflow problems
long range = (long)aEnd - (long)aStart + 1;
// compute a fraction of the range, 0 <= frac < range
long fraction = (long)(range * aRandom.nextDouble());
int randomNumber = (int)(fraction + aStart);
log("Generated : " + randomNumber);
}
private static void log(String aMessage){
System.out.println(aMessage);
}
}
Пример запуска этого класса:
Generating random integers in the range 1..10.
Generated : 9
Generated : 3
Generated : 3
Generated : 9
Generated : 4
Generated : 1
Generated : 3
Generated : 9
Generated : 10
Generated : 10
Done.
rand.nextInt((max+1) - min) + min;
Это нормально работает.
Использование:
minValue + rn.nextInt(maxValue - minValue + 1)
Чтобы сгенерировать случайное число «между двумя числами», используйте следующий код:
Random r = new Random();
int lowerBound = 1;
int upperBound = 11;
int result = r.nextInt(upperBound-lowerBound) + lowerBound;
Это дает вам случайное число от 1 (включительно) до 11 (исключительно), поэтому инициализируйте значение upperBound, добавив 1. Например, если вы хотите сгенерировать случайное число от 1 до 10, тогда инициализируйте число upperBound с помощью 11 вместо 10.
int random = minimum + Double.valueOf(Math.random()*(maximum-minimum )).intValue();
Или взгляните на RandomUtils из Apache Commons.
Double.valueOf(Math.random()*(maximum-minimun)).intValue()
— довольно запутанный (и неэффективный) способ сказать (int)(Math.random()*(maximum-minimun))
…
С помощью java-8они представили метод ints(int randomNumberOrigin, int randomNumberBound)
в Random
а> класс.
Например, если вы хотите сгенерировать пять случайных целых чисел (или одно) в диапазоне [0, 10], просто выполните:
Random r = new Random();
int[] fiveRandomNumbers = r.ints(5, 0, 11).toArray();
int randomNumber = r.ints(1, 0, 11).findFirst().getAsInt();
Первый параметр указывает только размер сгенерированного IntStream
(который является перегруженным методом того, который создает неограниченное IntStream
).
Если вам нужно сделать несколько отдельных вызовов, вы можете создать из потока бесконечный примитивный итератор:
public final class IntRandomNumberGenerator {
private PrimitiveIterator.OfInt randomIterator;
/**
* Initialize a new random number generator that generates
* random numbers in the range [min, max]
* @param min - the min value (inclusive)
* @param max - the max value (inclusive)
*/
public IntRandomNumberGenerator(int min, int max) {
randomIterator = new Random().ints(min, max + 1).iterator();
}
/**
* Returns a random number in the range (min, max)
* @return a random number in the range (min, max)
*/
public int nextInt() {
return randomIterator.nextInt();
}
}
Вы также можете сделать это для значений double
и long
. Я надеюсь, что это помогает! :)
Вы можете отредактировать свой второй пример кода следующим образом:
Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum = rn.nextInt(range) + minimum;
Достаточно небольшой модификации вашего первого решения.
Random rand = new Random();
randomNum = minimum + rand.nextInt((maximum - minimum) + 1);
Дополнительные сведения о реализации Random
ThreadLocalRandom
эквивалент класса java.util.Random
для многопоточной среды. Генерация случайного числа осуществляется локально в каждом из потоков. Таким образом, мы имеем лучшую производительность за счет уменьшения конфликтов.
int rand = ThreadLocalRandom.current().nextInt(x,y);
x
, y
- интервалы, например. (1,10)
Класс Math.Random
в Java основан на 0. Итак, если вы напишете что-то вроде этого:
Random rand = new Random();
int x = rand.nextInt(10);
x
будет между 0-9
включительно.
Таким образом, учитывая следующий массив элементов 25
, код для генерации случайного числа между 0
(основание массива) и array.length
будет таким:
String[] i = new String[25];
Random rand = new Random();
int index = 0;
index = rand.nextInt( i.length );
Поскольку i.length
вернет 25
, nextInt( i.length )
вернет число в диапазоне 0-24
. Другой вариант — Math.Random
, который работает точно так же.
index = (int) Math.floor(Math.random() * i.length);
Для лучшего понимания ознакомьтесь с сообщением на форуме Случайные интервалы (archive.org).
index
не повлияет на результат случайного числа. Вы можете инициализировать его любым удобным для вас способом, не беспокоясь об изменении результата. Надеюсь это поможет.
int index = rand.nextInt(i.Length);
int index; \n index = rand...
если вам нравятся объявления и присваивания в разных строках. Некоторые стандарты кодирования более строгие (и без видимой цели), чем другие.
Это можно сделать, просто выполнив оператор:
Randomizer.generate(0, 10); // Minimum of zero and maximum of ten
Ниже приведен его исходный код.
Файл Randomizer.java
public class Randomizer {
public static int generate(int min, int max) {
return min + (int)(Math.random() * ((max - min) + 1));
}
}
Это просто чисто и просто.
Простите меня за придирчивость, но решение, предложенное большинством, т. е. min + rng.nextInt(max - min + 1))
, кажется рискованным из-за того, что:
rng.nextInt(n)
не может связаться сInteger.MAX_VALUE
.(max - min)
может вызвать переполнение, еслиmin
имеет отрицательное значение.
Надежное решение вернет правильные результаты для любого min <= max
в пределах [Integer.MIN_VALUE
, Integer.MAX_VALUE
]. Рассмотрим следующую наивную реализацию:
int nextIntInRange(int min, int max, Random rng) {
if (min > max) {
throw new IllegalArgumentException("Cannot draw random int from invalid range [" + min + ", " + max + "].");
}
int diff = max - min;
if (diff >= 0 && diff != Integer.MAX_VALUE) {
return (min + rng.nextInt(diff + 1));
}
int i;
do {
i = rng.nextInt();
} while (i < min || i > max);
return i;
}
Хотя это неэффективно, обратите внимание, что вероятность успеха в цикле while
всегда будет 50 % или выше.
Интересно, будет ли работать любой из методов генерации случайных чисел, предоставляемых библиотекой Apache Commons Math? соответствовать счету.
Например: RandomDataGenerator.nextInt
или RandomDataGenerator.nextLong
Я использую это:
/**
* @param min - The minimum.
* @param max - The maximum.
* @return A random double between these numbers (inclusive the minimum and maximum).
*/
public static double getRandom(double min, double max) {
return (Math.random() * (max + 1 - min)) + min;
}
Вы можете привести его к целому числу, если хотите.
new Random
(проверьте JavaDoc): «Создает новый генератор случайных чисел. Этот конструктор устанавливает начальное значение генератора случайных чисел в значение, которое, скорее всего, будет отличаться от любого другого вызова этого конструктора». Скорее всего, это может быть просто использование текущего времени в качестве начального значения. Если это время использует миллисекунды, то современные компьютеры достаточно быстры, чтобы генерировать такое же число. Но помимо этого 2147483647 равно Integer.MAX_VALUE
; вывод, очевидно, зависит от ввода, который вы не указали.
rand.nextInt((max+1) - min) + min;
В случае броска игральной кости это будет случайное число от 1 до 6 (не от 0 до 6), поэтому:
face = 1 + randomNumbers.nextInt(6);
Вот полезный класс для генерации случайных ints
в диапазоне с любой комбинацией включающих/исключительных границ:
import java.util.Random;
public class RandomRange extends Random {
public int nextIncInc(int min, int max) {
return nextInt(max - min + 1) + min;
}
public int nextExcInc(int min, int max) {
return nextInt(max - min) + 1 + min;
}
public int nextExcExc(int min, int max) {
return nextInt(max - min - 1) + 1 + min;
}
public int nextIncExc(int min, int max) {
return nextInt(max - min) + min;
}
}
Вы можете добиться этого в Java 8:
Random random = new Random();
int max = 10;
int min = 5;
int totalNumber = 10;
IntStream stream = random.ints(totalNumber, min, max);
stream.forEach(System.out::println);
Другой вариант — просто использовать Apache Commons:
import org.apache.commons.math.random.RandomData;
import org.apache.commons.math.random.RandomDataImpl;
public void method() {
RandomData randomData = new RandomDataImpl();
int number = randomData.nextInt(5, 10);
// ...
}
Вот простой пример, который показывает, как сгенерировать случайное число из закрытого диапазона [min, max]
, а min <= max is true
Вы можете повторно использовать его как поле в классе отверстий, а также иметь все методы Random.class
в одном месте.
Пример результатов:
RandomUtils random = new RandomUtils();
random.nextInt(0, 0); // returns 0
random.nextInt(10, 10); // returns 10
random.nextInt(-10, 10); // returns numbers from -10 to 10 (-10, -9....9, 10)
random.nextInt(10, -10); // throws assert
Источники:
import junit.framework.Assert;
import java.util.Random;
public class RandomUtils extends Random {
/**
* @param min generated value. Can't be > then max
* @param max generated value
* @return values in closed range [min, max].
*/
public int nextInt(int min, int max) {
Assert.assertFalse("min can't be > then max; values:[" + min + ", " + max + "]", min > max);
if (min == max) {
return max;
}
return nextInt(max - min + 1) + min;
}
}
Лучше использовать SecureRandom, а не просто Random. .
public static int generateRandomInteger(int min, int max) {
SecureRandom rand = new SecureRandom();
rand.setSeed(new Date().getTime());
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
private static int SecureRandom rand = new SecureRandom();
2: static {
3: rand.setSeed(...);
4: }
SecureRandom
, он будет раздаваться системой. Прямой вызов setSeed
очень опасен, он может заменить (действительно случайное) начальное число датой. И это, безусловно, не приведет к SecureRandom
, так как любой может угадать время и попытаться заполнить свой собственный экземпляр SecureRandom
этой информацией.
public static Random RANDOM = new Random(System.nanoTime());
public static final float random(final float pMin, final float pMax) {
return pMin + RANDOM.nextFloat() * (pMax - pMin);
}
В Java 1.7 или более поздних версиях это можно сделать следующим образом:
import java.util.concurrent.ThreadLocalRandom;
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = ThreadLocalRandom.current().nextInt(min, max + 1);
См. соответствующий JavaDoc. Этот подход имеет то преимущество, что не нужно явно инициализировать java.util.Random, который может стать источником путаницы и ошибок при неправильном использовании.
Однако, наоборот, нет способа явно установить начальное значение, поэтому может быть сложно воспроизвести результаты в ситуациях, когда это полезно, например, при тестировании или сохранении игровых состояний и т.п. В таких ситуациях можно использовать описанную ниже методику до версии Java 1.7.
До Java 1.7 стандартный способ сделать это был следующим:
import java.util.Random;
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
* <code>Integer.MAX_VALUE - 1</code>.
*
* @param min Minimum value
* @param max Maximum value. Must be greater than min.
* @return Integer between min and max, inclusive.
* @see java.util.Random#nextInt(int)
*/
public static int randInt(int min, int max) {
// NOTE: This will (intentionally) not run as written so that folks
// copy-pasting have to think about how to initialize their
// Random instance. Initialization of the Random instance is outside
// the main scope of the question, but some decent options are to have
// a field that is initialized once and then re-used as needed or to
// use ThreadLocalRandom (if using at least Java 1.7).
//
// In particular, do NOT do 'Random rand = new Random()' here or you
// will get not very good / not very random results.
Random rand;
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
См. соответствующий JavaDoc. На практике java Класс .util.Random часто предпочтительнее java.lang.Math.random().
В частности, нет необходимости заново изобретать колесо генерации случайных целых чисел, когда в стандартной библиотеке есть простой API для выполнения этой задачи.
max
равно Integer.MAX_VALUE
, возможно переполнение, что приводит к java.lang.IllegalArgumentException
. Вы можете попробовать с: randInt(0, Integer.MAX_VALUE)
. Кроме того, если nextInt((max-min) + 1)
возвращает самое высокое значение (я полагаю, довольно редко), не будет ли оно снова переполняться (предположим, что min и max являются достаточно высокими значениями)? Как вести себя в подобных ситуациях?
Использование:
Random ran = new Random();
int x = ran.nextInt(6) + 5;
Целое число x
теперь является случайным числом, которое может иметь результат 5-10
.
Сгенерируйте случайное число для разницы минимального и максимального значений с помощью nextint(n), а затем добавить минимальное число к результату:
Random rn = new Random();
int result = rn.nextInt(max - min + 1) + min;
System.out.println(result);
Просто используйте класс Random:
Random ran = new Random();
// Assumes max and min are non-negative.
int randomInt = min + ran.nextInt(max - min + 1);
Эти методы могут быть удобными для использования:
Этот метод вернет случайное число между указанным минимальным и максимальным значением:
public static int getRandomNumberBetween(int min, int max) {
Random foo = new Random();
int randomNumber = foo.nextInt(max - min) + min;
if (randomNumber == min) {
// Since the random number is between the min and max values, simply add 1
return min + 1;
} else {
return randomNumber;
}
}
И этот метод вернет случайное число из указанного минимального и максимального значения (поэтому сгенерированное число также может быть минимальным или максимальным числом):
public static int getRandomNumberFrom(int min, int max) {
Random foo = new Random();
int randomNumber = foo.nextInt((max + 1) - min) + min;
return randomNumber;
}
// Since the random number is between the min and max values, simply add 1
. Почему? Мин не считается? Обычно диапазон составляет [min, max), где min включено, а max исключено. Неправильный ответ, проголосовал против.
min + 1
будет в два раза больше, чем другое число, будет результатом getRandomNumberBetween
!
Обратите внимание, что этот подход более предвзят и менее эффективен, чем подход nextInt
, https://stackoverflow.com/a/738651. /360211
Один стандартный шаблон для достижения этого:
Min + (int)(Math.random() * ((Max - Min) + 1))
Функция Math.random() Java Math.random() генерирует двойное значение в диапазоне [0,1)
. Обратите внимание, что этот диапазон не включает 1.
Чтобы сначала получить определенный диапазон значений, вам нужно умножить на величину диапазона значений, который вы хотите охватить.
Math.random() * ( Max - Min )
Это возвращает значение в диапазоне [0,Max-Min)
, где "Max-Min" не включено.
Например, если вы хотите [5,10)
, вам нужно покрыть пять целочисленных значений, поэтому вы используете
Math.random() * 5
Это вернет значение в диапазоне [0,5)
, где 5 не включено.
Теперь вам нужно сместить этот диапазон до диапазона, на который вы нацеливаетесь. Вы делаете это, добавляя значение Min.
Min + (Math.random() * (Max - Min))
Теперь вы получите значение в диапазоне [Min,Max)
. В нашем примере это означает [5,10)
:
5 + (Math.random() * (10 - 5))
Но это все еще не включает Max
, и вы получаете двойное значение. Чтобы включить значение Max
, вам нужно добавить 1 к вашему параметру диапазона (Max - Min)
, а затем усечь десятичную часть, приведя к целому числу. Это достигается за счет:
Min + (int)(Math.random() * ((Max - Min) + 1))
И вот оно. Случайное целочисленное значение в диапазоне [Min,Max]
или, например, [5,10]
:
5 + (int)(Math.random() * ((10 - 5) + 1))
Похожие вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.