Ответ 1
Вопрос 1:, если n - малая степень 2, последовательность генерируемых случайных чисел будет повторяться через короткий промежуток времени.
Это не является следствием всего, что говорит Джош; скорее, это просто известное свойство линейных конгруэнтных генераторов. Википедия должна сказать следующее:
Еще одна проблема LCG заключается в том, что младшие разряды сгенерированной последовательности имеют гораздо более короткий период, чем последовательность в целом, если m задано степенью 2. В общем случае n-я младшая значащая цифра в базовом b представлении выходной последовательности, где b k= m для некоторого целого k, повторяется с не более чем периодом b n.
Это также отмечается в Javadoc:
Известно, что линейные конгруэнтные генераторы псевдослучайных чисел, такие как реализованные этим классом, имеют короткие периоды в последовательности значений их младших разрядов.
Другая версия функции Random.nextInt(int)
работает вокруг этого, используя в этом случае разные биты (выделение мое):
Алгоритм рассматривает случай, когда n - это сила двух специально: он возвращает правильное количество старших бит из генератора псевдослучайных чисел.
Это хорошая причина предпочесть Random.nextInt(int)
с помощью Random.nextInt()
и сделать собственное преобразование диапазона.
Вопрос 2: Далее он говорит, что если n не является степенью 2, некоторые числа будут возвращаться в среднем чаще, чем другие.
Есть 2 32 различные числа, которые могут быть возвращены nextInt()
. Если вы попытаетесь поместить их в n ведер, используя % n
, а n не имеет значения 2, некоторые ведра будут иметь больше чисел, чем другие. Это означает, что некоторые результаты будут происходить чаще, чем другие, хотя исходное распределение было однородным.
Посмотрите на это, используя небольшие числа. Скажем, nextInt()
вернул четыре равновероятных результата: 0, 1, 2 и 3. Посмотрим, что произойдет, если мы применим к ним % 3
:
0 maps to 0
1 maps to 1
2 maps to 2
3 maps to 0
Как вы можете видеть, алгоритм будет возвращать 0 в два раза чаще, чем возвращать каждый из 1 и 2.
Это не происходит, когда n является степенью двух, так как одна степень из двух делится на другую. Рассмотрим n=2
:
0 maps to 0
1 maps to 1
2 maps to 0
3 maps to 1
Здесь 0 и 1 происходят с одинаковой частотой.
Дополнительные ресурсы
Вот некоторые дополнительные - если только касательно релевантные - ресурсы, связанные с LCG:
- Спектральные тесты - это статистические тесты, используемые для оценки качества LCG. Подробнее здесь и здесь.
- Коллекция классических генераторов псевдослучайных чисел с линейными структурами имеет несколько симпатичных диаграмм рассеяния (генератор, используемый в Java, называется DRAND48).
- В crypto.SE есть интересная дискуссия о прогнозировании значений из генератора Java.