Дозвольте мені заздалегідь вибачитися, тому що це трохи важко зрозуміти ...
Перш за все, ви вже знаєте, що 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).