Мой настоящий вопрос в том, является ли вариант 1 математически действительным.
Начнем с опцией 2. Генератор случайных чисел, используемый java.util.Random
указан в Javadoc следующим образом:
Класс использует 48-битное семя, которое модифицирована с использованием линейной конгруэнтной формулу , (См. Дональд Кнут, «Искусство компьютерного программирования», том 2, раздел 3.2.1.)
и есть более конкретные детали в javadocs различных методов.
Но дело в том, что мы используем последовательность, порожденную линейной конгруэнтной формулой, и такие формулы имеют значительную степень автокорреляции ... что может быть проблематичным.
Теперь с опцией 1 вы используете другой экземпляр Random
с новым семенем каждый раз и применяете один раунд формулы LC. Таким образом, вы получаете последовательность чисел, которые, вероятно, будут автокоррелированы с семенами. Однако семена генерируются по-разному, в зависимости от версии Java.
Java 6 делает это:
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
... что не очень случайных вообще. Если вы создали Random
экземпляров с постоянным интервалом, семена, вероятно, будут расположены близко друг к другу, и поэтому последовательность случайных чисел, созданных вашей опцией №1, может быть автоматически коррелирована.
В отличие от Java 7 и 8 это сделать:
public Random() {
this(seedUniquifier()^System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
Последовательность семян, полученных выше, вероятно, будет гораздо лучшее приближение к истинному() случайности. Вероятно, ваш вариант №1 превосходит вариант №2.
Недостатком вашей опции № 1 в Java с 6 по 8 является то, что System.nanoTime()
, вероятно, вызывает системный вызов. Это относительно дорого.
Поэтому короткий ответ, что это Java от версии, которая опция # 1 и # 2 варианта дает лучшие качества «случайным» числа ... с математической точки зрения.
В обоих случаях распределение чисел будет равномерным на достаточно большом размере выборки, хотя я не уверен, что имеет смысл говорить о распределении вероятностей, когда процесс детерминирован.
Однако ни один из подходов не был бы подходящим как генератор случайных чисел криптосилы.
перейти с опцией 3: 'ThreadLocalRandom.current(). NextInt()'. Также вы ошибаетесь в отношении рандомов одновременно, http://stackoverflow.com/a/20060801/995891 не только использует время для инициализации. – zapl
Спасибо, что я не знал об этом. Я обновлю вопрос –