Позвольте мне заранее извиниться, потому что это немного сложно понять ...
Прежде всего, вы уже знаете, что java.util.Random
это не совсем случайно. Он генерирует последовательности совершенно предсказуемым образом из семян. Вы совершенно правы, поскольку, поскольку начальное число имеет длину всего 64 бита, оно может генерировать только 2 ^ 64 различных последовательностей. Если бы вы как-то сгенерировали 64 реальных случайных бита и использовали их для выбора начального числа, вы не могли бы использовать этот начальный случайный выбор между всеми этими 52! возможные последовательности с равной вероятностью.
Однако этот факт не имеет никакого значения, если вы на самом деле не собираетесь генерировать более 2 ^ 64 последовательностей, если нет ничего «особенного» или «заметно особенного» в последовательностях 2 ^ 64, которые он может генерировать ,
Допустим, у вас был намного лучший PRNG, который использовал 1000-битные семена. Представьте, что у вас есть два способа его инициализации - один из них будет инициализировать его с использованием всего начального числа, а один - хинизировать начальное значение до 64 битов перед его инициализацией.
Если вы не знаете, какой это был инициализатор, можете ли вы написать какой-либо тест, чтобы различить их? Если вам не повезло (в итоге) инициализировать плохой с одинаковыми 64 битами дважды, тогда ответ - нет. Вы не могли бы различить два инициализатора, не зная некоторых слабых мест в конкретной реализации PRNG.
В качестве альтернативы представьте, что Random
класс имел массив из 2 ^ 64 последовательностей, которые были выбраны полностью и случайным образом в какое-то время в далеком прошлом, и что начальное число было просто индексом в этом массиве.
Так что тот факт, что Random
использует только 64 бита для своего начального числа, на самом деле не является статистически проблемой, если не существует значительного шанса, что вы будете использовать одно и то же начальное число дважды.
Конечно, для криптографических целей 64-разрядного начального числа просто недостаточно, поскольку получение системой, использующей одно и то же начальное число дважды, вычислительно возможно.
РЕДАКТИРОВАТЬ:
Я должен добавить, что, хотя все вышеперечисленное является правильным, фактическая реализация java.util.Random
не является удивительной. Если вы пишете карточную игру, возможно, используйте MessageDigest
API для генерации хэша SHA-256 "MyGameName"+System.currentTimeMillis()
и используйте эти биты для перетасовки колоды. По приведенному выше аргументу, пока ваши пользователи на самом деле не играют в азартные игры, вам не нужно беспокоиться о том, что currentTimeMillis
возвращает долго. Если ваши пользователи действительно играют в азартные игры, то используйте SecureRandom
без начальных затрат.
Random
никогда не являются реальными случайными числами. Это PRNG, где P означает «псевдо». Для реальных случайных чисел вам нужен источник случайности (например, random.org).