Java Random, небольшое изменение в семени вызывает только небольшое изменение в выводе - PullRequest
8 голосов
/ 28 мая 2011

При создании генератора карт в Java я обнаружил довольно неприятную проблему с их генератором случайных чисел, чтобы указать, когда два RNG имеют очень похожие начальные числа (отличающиеся маленькими целыми числами), их первое выходное значение станет очень похожим!

Пример кода:

Random r = new Random();
long n = 100000; //Choose any number
r.setSeed(n);  
System.out.println(r.nextInt());
r.setSeed(n+1);
System.out.println(r.nextInt());

Это в значительной степени сломало мою веру в исходный Java RNG, поскольку я использую координаты для заполнения генератора карт.Может ли кто-нибудь предложить переопределение метода Random.next(int bits) или другое исправление этой проблемы?

Спасибо за помощь!

Ответы [ 4 ]

8 голосов
/ 29 мая 2011

сравнивали ли вы последовательность первых ~ 20 значений, полученных из 100000 и 100001?

это первые 20 следующих семян 100000 и 100001 соответственно. с в третьем столбце количество различных битов (число битов xor между 2)

этот последний столбец должен оставаться около 16

-1986972922 -1987357671 13
-1760380366 -604895790  16
-1057894078 -329706441  15
-363772240  -1218064509 15
1545317691  -300240831  14
271304166   -900428132  21
1208561582  273461468   16
-1257783052 1069490639  16
-1549884799 40157720    15
-1514737808 -1818800021 17
-1030569735 1859508545  15
1310070992  880402584   18
-1513092400 971613287   19
-1993219517 354161779   16
-10847170   -204018237  15
-965377044  1488135032  14
802471291   1094582308  22
-539776032  -1021376555 15
2088199751  2070302462  12
-1271582124 64627614    19

не очень похоже после 3-5 итераций он

помимо стандарта Random реализует линейный конгруэнтный ГСЧ, который, как известно, не является лучшей псевдослучайной реализацией из существующих, но наиболее эффективен с памятью (только одно 64-битное слово за период 2^48)

для заинтересованного множитель 0x5deece66dL, а c 0xbL

2 голосов
/ 28 мая 2011

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

В любом случае вы не должны использовать Random.Состояние PRNG будет обновляться (состояние / начальное значение будет меняться примерно на 50% из 48 доступных битов) при каждом методе nextInt.Это все, о чем ты должен заботиться.

1 голос
/ 29 мая 2011

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

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

0 голосов
/ 29 мая 2011

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

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

...