Java random всегда возвращает одно и то же число, когда я устанавливаю начальное число?

Мне нужна помощь с генератором случайных чисел, который я создаю. Мой код выглядит следующим образом (внутри класса, называемого числами):

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. Что мне нужно сделать, чтобы он печатал два разных номера, например, 5 8

Обязательно, чтобы я установил семя.

Спасибо

7 ответов

Решение

Вы должны поделиться Random() экземпляр по всему классу:

public class Numbers {
    Random randnum;

    public Numbers() {
        randnum = new Random();
        randnum.setSeed(123456789);
    }

    public int random(int i){
        return randnum.nextInt(i);
    }
}

Если вы всегда устанавливаете семя, вы всегда получите один и тот же ответ. Это то, что делает установка.

Есть две проблемы, вызывающие то, что вы видите. Во-первых, код устанавливает начальное значение для экземпляра Random. Во-вторых, метод экземпляра "random" создает новый объект Random, а затем немедленно каждый раз устанавливает его начальное число с одним и тем же начальным значением. Комбинация этих двух гарантирует, что при одном и том же значении i метод "random" всегда будет возвращать одно и то же значение и всегда будет первым в последовательности, которую всегда генерирует начальное число.

Предполагая, что установка начального числа является обязательной, чтобы каждый раз получать следующее значение в последовательности вместо одного и того же первого значения последовательности, экземпляру randnum в Random не может быть задано начальное число каждый раз перед вызовом следующего метода. Чтобы это исправить, переместите экземпляр локальной переменной randnum объекта Random из области действия метода random в область класса. Во-вторых, устанавливайте начальное значение только в том случае, если случайному назначен случайный экземпляр или только для того, чтобы получить из него ту же последовательность результатов для повторного запуска. Метод экземпляра setSeed (long seed) класса Random не может выполняться в области видимости класса, поэтому конструктор должен установить его с помощью конструктора 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(long seed)

и метод экземпляра

setSeed(long seed)

это все влияет на последовательность чисел, полученных из случайного экземпляра. Метод экземпляра,

setSeed(long seed)

устанавливает объект Random в то же состояние, в котором он находился бы, если бы он был просто создан с тем же начальным значением, что и аргумент конструктора. Используются только младшие 48 битов начального значения.

Если случайный объект создается без начального числа, начальное число будет таким же, как системное время в миллисекундах. Это гарантирует, что, если два объекта Random не будут созданы в одну и ту же миллисекунду, они будут создавать разные псевдослучайные последовательности. Используются только младшие 48 битов начального значения. Это вызывает непредсказуемые псевдослучайные последовательности. Нет необходимости и не нужно тратить вычислительные ресурсы на получение нового экземпляра Random каждый раз, когда вызывается следующий метод.

Начальные параметры Random предоставляются таким образом, чтобы можно было создать экземпляр объекта Random, который создает последовательность, которая повторяется. Для данного начального числа последовательность значений в следующих методах гарантированно будет одной и той же последовательностью при каждом использовании этого начального числа. Это полезно для тестирования программного обеспечения, которое будет использовать псевдослучайные последовательности, где результаты должны быть предсказуемыми и повторяемыми. Это бесполезно для создания различных непредсказуемых псевдослучайных последовательностей в действии.

Утверждение "я обязательно задаю начальное число" сводит на нет любую непредсказуемость псевдослучайных последовательностей объекта Random. Это для классного проекта или теста программного обеспечения, где результаты должны быть одинаковыми для одних и тех же входов в программу?

Установите начальное значение один раз при запуске, а не каждый раз, когда вы хотите новое случайное число.

То, что вы используете, это не генератор случайных чисел, это генератор псевдослучайных чисел. PRNG генерирует последовательности псевдослучайных чисел, начальное число выбирает начальную точку в последовательности (PRNG может генерировать одну или несколько последовательностей).

Обычно Random не является действительно случайным, а псевдослучайным. Это означает, что он берет заданное начальное число и использует его для генерации последовательности чисел, которые выглядят как случайные (но полностью предсказуемы и повторяются, если вы положили то же самое начальное число).

Если вы не положите начальное значение, то первое начальное значение будет взято из переменного источника (обычно системного времени).

Обычно значение с начальным значением используется для повторения точных значений (например, для тестирования). Вместо этого используйте Random без семян.

Вам обязательно нужно создать new Random() внутри вашего random(int i) метод? Если вы ОБЯЗАНЫ делать это таким образом, вы можете использовать, вы можете установить начальное значение на текущее время, хотя это не является доказательством сбоя, потому что вы можете вызвать numbers.random(10) так быстро за другим, что в итоге получится то же самое семя. Вы можете попробовать использовать nanoSeconds (я думаю, System.nanoTime()? И если setSeed принимает только int, я думаю, умножьте его).

Однако я бы предложил, если вам разрешено это сделать, - объявить свой Random вне вашего метода. Если вы создаете свою случайную переменную, скажем, в number конструктор класса, вы можете установить любое начальное число, и каждый раз, когда вы вызываете ваш метод, он дает вам новый номер. (Они будут одинаковыми наборами чисел каждый раз, когда вы перезапускаете свое приложение, если вы используете постоянное начальное число, однако в этом случае вы также можете использовать время в качестве начального числа).

Наконец, последняя проблема может быть, если вы объявите несколько number занятия одновременно. Все они будут иметь одинаковое случайное число и дать вам одинаковый набор случайных чисел. Если это произойдет, вы можете сделать static Random в вашем основном классе, и назовите это в своем классе чисел. Это соединит эти два класса, но это сработает. Другим вариантом будет отправить возрастающее значение на ваш number конструктор класса, для каждого number вы воплощаете и используете значение, которое вы передаете, как семя.

Второй вариант должен быть вам полезен, если вам разрешено делать это таким образом.

Другие вопросы по тегам