Случайность Java всегда возвращает тот же номер, когда я устанавливаю семя?
Мне нужна помощь с генератором случайных чисел, который я создаю. Мой код выглядит следующим образом (внутри класса с номерами):
public int random(int i){
Random randnum = new Random();
randnum.setSeed(123456789);
return randnum.nextInt(i);
}
Когда я вызываю этот метод из другого класса (для генерации случайного числа), он всегда возвращает тот же номер. Например, если бы я сделал:
System.out.println(numbers.random(10));
System.out.print(numbers.random(10));
он всегда печатает одинаковое число, например. 5. Что мне нужно сделать, чтобы он печатал два разных числа, например. 5 8
Обязательно, чтобы я установил семя.
Спасибо
Ответы
Ответ 1
Вам нужно разделить экземпляр Random()
по всему классу:
public class Numbers {
Random randnum;
public Numbers() {
randnum = new Random();
randnum.setSeed(123456789);
}
public int random(int i){
return randnum.nextInt(i);
}
}
Ответ 2
Если вы всегда задаете семя, вы всегда получите тот же ответ. Это то, что устанавливает семя.
Ответ 3
Есть две проблемы, вызывающие то, что вы видите. Во-первых, код устанавливает начальное значение для экземпляра Random. Во-вторых, метод экземпляра "случайный" создает новый случайный объект, а затем сразу же устанавливает его семя с одним и тем же семенем каждый раз. Сочетание этих двух гарантий, что при одном и том же значении я метод "случайный" всегда будет возвращать одно и то же значение, и он всегда будет первым в последовательности, которую семя всегда генерирует.
Предполагая, что установка семени является обязательной, чтобы получить следующее значение в последовательности, а не одно и то же первое значение последовательности каждый раз, экземпляр randnum из Random не может иметь свой набор семян каждый раз перед тем, как его следующий метод получит называется. Чтобы исправить это, переместите экземпляр локальной переменной randnum из Random из области действия метода случайного экземпляра в область класса. Во-вторых, установите семя только тогда, когда случайному назначается случайный экземпляр или только для получения той же последовательности результатов от него, чтобы начать заново. Класс Случайный метод setSeed (long seed) не может выполняться в области видимости класса, поэтому конструктор должен установить его с помощью конструктора Random с параметром long seed. Следующий код показывает изменения:
public class RandomDemo { // arbitrary example class name
// lots of class related stuff may be here...
// still inside the class scope...
// private is a good idea unless an external method needs to change it
private Random randnum = new Random(123456789L);
// the seed guarantees it will always produce the same sequence
// of pseudo-random values when the next methods get called
// for unpredicable sequences, use the following constructor instead:
// private Random randnum = new Random();
// lots of code may be here...
// publicly exposed instance method for getting random number
// from a sequence determined by seed 123456789L
// in the range from 0 through i-1
public int randnum(int i) {
// don't set the seed in here, or randnum will return the exact same integer
// for the same value of i on every method call
// nextInt(i) will give the next value from randnum conforming to range i
return randnum.nextInt(i);
} // end randnum
// lots of more code may be here...
} // end class RandDemo
Вышеупомянутое даст вам точное решение вашей конкретной проблемы, как указано. Однако использование обязательного семени кажется необычным, учитывая то, что он делает.
Если это для проекта класса или тестирования программного обеспечения, где последовательность должна быть предсказуемой и повторяемой, установка семени на фиксированное значение имеет смысл. В противном случае задайте вопрос о правильности установки семени на некоторое заданное значение. Ниже объясняется больше о Random, семенах для Random и почему существует условие для предоставления семени.
Случайное имеет два конструктора:
Random()
и
Random(long seed)
и метод экземпляра
setSeed(long seed)
что все влияет на последовательность чисел, полученных из случайного экземпляра. Метод экземпляра
setSeed(long seed)
устанавливает случайный объект в том же состоянии, в котором он находился бы, если бы он был только с тем же семенем, что и аргумент конструктора. Используются только младшие 48 бит начального значения.
Если случайный объект задан без семени, семя будет таким же, как и системное время в миллисекундах. Это гарантирует, что, если в одной и той же миллисекунде не установлены два случайных объекта, они будут создавать разные псевдослучайные последовательности. Используются только младшие 48 бит начального значения. Это приводит к непредсказуемым псевдослучайным последовательностям. Не нужно и расточительно вычислить ресурсы для получения нового экземпляра Random каждый раз, когда вы вызываете следующий метод.
Предусмотрены случайные параметры семян, чтобы можно было случайным объектом создать последовательность, которая повторяется. Для данного семени последовательность значений в следующих методах гарантированно будет одной и той же последовательностью всякий раз, когда используется это семя. Это полезно для тестирования программного обеспечения, которое будет использовать псевдослучайные последовательности, где результаты должны быть предсказуемыми и повторяемыми. Это не полезно для создания различных непредсказуемых псевдослучайных последовательностей в работе.
Утверждение "обязательно, чтобы я установил семя" отрицает любую непредсказуемость псевдослучайных последовательностей Random. Это для проекта класса или программного теста, где результаты должны быть одинаковыми для одних и тех же входных данных для программы?
Ответ 4
Устанавливайте семя один раз при запуске, а не каждый раз, когда вы хотите получить новое случайное число.
Ответ 5
То, что вы используете, не является генератором случайных чисел, это генератор псевдослучайных чисел. PRNG генерирует последовательности псевдослучайных чисел, семя выбирает начальную точку в последовательности (PRNG может генерировать одну или несколько последовательностей).
Ответ 6
Вам обязательно нужно создать new Random()
внутри вашего метода random(int i)
? Если вы ОБЯЗАТЕЛЬНЫ, чтобы сделать это таким образом, вы могли бы использовать, вы могли бы установить семя на текущее время, хотя это не подлежит проверке, потому что вы могли бы быстро вызвать ваш numbers.random(10)
после другого, чтобы он оказался одно и то же семя. Вы можете попробовать, возможно, использовать nanoSeconds (System.nanoTime(), я думаю? И если setSeed принимает только int, умножьте его, я думаю).
Что я хотел бы предложить, если вам разрешено это сделать, объявить ваш случайный внешний ваш метод. Если вы производите произвольную переменную в, скажем, в своем конструкторе класса number
, вы можете установить любое семя, и в любое время, когда вы вызовете свой метод, он даст вам новый номер. (Они будут одинаковыми наборами чисел при каждом повторном запуске приложения, если вы используете постоянное семя, однако в этом случае вы также можете использовать время в качестве семени).
Наконец, последняя проблема может заключаться в том, что вы объявляете несколько классов number
в одно и то же время. Все они будут иметь одинаковое случайное семя и дают вам один и тот же набор случайных чисел. Если это произойдет, вы можете сделать static Random
в своем основном классе и вызвать его в своем классе чисел. Это будет сопрягать эти два класса, хотя, но это сработает. Другой вариант - отправить инкрементное значение в конструктор класса number
, для каждого number
, который вы инициируете, и использовать значение, которое вы передаете как семя.
Второй вариант должен быть хорошим для вас, если вам разрешено делать это таким образом.
Ответ 7
Обычно Random не является по-настоящему случайным, но псевдослучайным. Это означает, что он принимает заданное семя и использует его для генерации последовательности чисел, которая выглядит как случайная (но она непредсказуема и повторяется, если вы помещаете одно и то же семя).
Если вы не поместите семя, то первое семя будет взято из источника переменной (обычно это системное время).
Обычно значение с семенем будет использоваться для повторения точных значений (например, для тестирования). Вместо этого используйте Random без семян.