При каких обстоятельствах вы хотели бы иметь другое начальное значение для вашего генератора случайных чисел?

#java #random #probability

#java #Случайный #вероятность

Вопрос:

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

 // same seed
class A {
    private Random random;
    public A() { random = new Random(); }
    public int nextInt() { return random.nextInt(10000); }
    public double nextDouble() { return random.nextDouble(); }
}
  

против

 // different seed is used every time when you call the method
class B {
    public int nextInt() { return new Random().nextInt(10000); }
    public double nextDouble() { return new Random().nextDouble(); }
}
  

Пожалуйста, игнорируйте этот дизайн для этих двух классов-оболочек, просто пытаясь показать разницу.

Комментарии:

1. Я думаю, что практика, продемонстрированная class B , является просто ошибкой. Оно зависит от системы заполнения по умолчанию, которая должна быть такого же или лучшего качества, чем дизайн PRNG, и это небезопасное предположение. Если вы видите это расположение в рабочем коде, было бы уместно оспорить его.

Ответ №1:

Две причины повторного использования Random :

  • Создание Random накладных расходов.

  • Если код быстрый, создание двух разных Random объектов может в конечном итоге привести к использованию одного и того же начального значения, т. Е. Результат не будет случайным. Даже если код не такой быстрый, разные Random объекты будут заполнены тесно связанными начальными значениями, уменьшая коэффициент случайности.

Одна из причин наличия нескольких Random экземпляров, хотя и не причина для создания нового при каждом использовании. Цитирование javadoc:

Экземпляры java.util.Random являются потокобезопасными. Однако одновременное использование одного и того же java.util.Random экземпляра в разных потоках может привести к конфликту и, как следствие, к снижению производительности. Рассмотрите возможность использования ThreadLocalRandom в многопоточных проектах.

Даже в однопоточном приложении использование ThreadLocalRandom может быть целесообразным в качестве простого средства получения общего Random экземпляра.

Комментарии:

1. Итак, в 99% случаев одного случайного объекта должно быть достаточно, правильно?

2. Это правильно. Как упоминает Джон Боллингер в конце своего ответа, если у вас есть два независимых фрагмента кода, которым обоим нужны случайные значения, они могут независимо создавать свой собственный экземпляр Random для «организационной» простоты. Но кроме этого, однопоточное приложение редко создает несколько экземпляров.

3. Я не понимаю одновременного использования, которое привело бы к последующей низкой производительности. Не могли бы вы подробнее рассказать об этом, пожалуйста

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

5. Полностью имеет смысл. Спасибо!

Ответ №2:

Генератор псевдослучайных чисел, такой как java.util.Random , выдает детерминированную последовательность чисел, характеризующуюся начальным значением. Такие генераторы создаются для создания последовательностей, которые, по-видимому, изменяются случайным образом и (обычно) равномерно по всему диапазону PRNG.

Вы получите ту же последовательность чисел, если начнете с одного и того же начального числа. Это может быть полезно при некоторых обстоятельствах, но обычно это нежелательно. В частности, ваши числа вообще не будут выглядеть случайными, если вы заполняете PRNG одним и тем же начальным значением перед генерацией каждого числа.

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

Итак, когда вы говорите

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

, единственная причина, по которой я могу придумать, почему я хочу изменить начальное значение в течение одного запуска вашей программы, заключается в том, что вы опубликовали достаточно результатов из PRNG, что вы обеспокоены тем, что кто-то определяет его реализацию и внутреннее состояние и, следовательно, может предсказать последующие числа. На практике это было бы проблемой только при довольно особых обстоятельствах.

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

Как правило, вы должны заполнить свой PRNG один раз, а затем использовать его столько, сколько необходимо, без повторного заполнения. Не обязательно неправильно использовать несколько независимых PRNG, но причины для этого в основном организационные (например, не нужно беспокоиться о синхронизации, не нужно обеспечивать внедрение Random экземпляра), а не функциональные.

Ответ №3:

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

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

Для большинства применений вам понадобится начальное значение по умолчанию, но может быть очень полезно предоставить вашему приложению возможность запуска с заранее определенным начальным значением; например:

   if (seedInputValueProvided)
    mRandom = new Random(seedInputValue);
  else
    mRandom = new Random();
  

Зачем это делать? Тестирование. Разработка. Если вы создаете ровно один случайный объект и повторно используете его с известным начальным значением, вы можете повторно запускать определенные сценарии для многократного тестирования одного и того же (или повторно создавать проблемы).