Дублирование случайных чисел из Java Secure Random

#java #random

#java #Случайный

Вопрос:

Я ожидаю уникальных случайных чисел из следующего Callable :

 public class UniqueGenerator implements Callable<Integer> {

    private static SecureRandom rnd;

    static {
        try {
            rnd = SecureRandom.getInstance("SHA1PRNG");
            rnd.setSeed(UUID.randomUUID().toString().getBytes());
        } catch (NoSuchAlgorithmException e) {
        }
    }

    @Override
    public Integer call() throws Exception {
        return rnd.nextInt();

    }
}
  

Однако из 1 000 000 выполнений этого метода я никогда не получаю 1 000 000 уникальных целых чисел.
Есть ли какой-либо способ, которым я могу когда-либо получить желаемый результат?
Какие ошибки я допустил при попытке сгенерировать уникальные целые числа?

Комментарии:

1. Конечно, они не уникальны. Они случайны.

2. Да; ваша проблема в том, что вы ожидаете чего-то, для чего генератор случайных чисел не предназначен. Это могло бы возвращать 1 каждый раз (маловероятно, но возможно), и это все равно было бы случайным. Если вам нужны уникальные числа, вам понадобится совершенно другой алгоритм.

Ответ №1:

Если вам нужны 1 000 000 уникальных случайных целых чисел, создайте объект, ArrayList содержащий Integer объекты от 0 до 999 999, а затем перетасуйте этот список, используя ваш SecureRandom объект:

 Collections.shuffle(cards, secureRandom);
  

Затем используйте целые числа по мере необходимости и воссоздайте список, если он пуст.

Комментарии:

1. Спасибо, что нашли время ответить, я чувствую, что ваш подход — единственный, который мне нужно использовать, чтобы получить желаемый результат

Ответ №2:

Конечно, они не будут уникальными. Они будут случайными. Для псевдогенератора случайных чисел совершенно удобно выдавать обратно то же число, которое он уже создал. Если вы запускаете его достаточно долго, например, 2 ^ 32 раза, вы не получите 2 ^ 32 уникальных числа. Многие числа будут повторяться. Если вам нужны уникальные случайные значения, идентификаторы UUID являются хорошим началом (хотя они не гарантированно уникальны — они предназначены для всех практических целей.)

Ответ №3:

Если вам нужен миллион уникальных чисел в случайном порядке, я бы использовал Collections.shuffle() . Например,

 List<Integer> al = new ArrayList<>();
for (int i = 0; i < 1000 * 1000; i  ) {
  al.add(i);
}
Collections.shuffle(al);
// al contains 1,000,000 numbers in random order.
  

Ответ №4:

Это парадокс дня рождения. Ваш interger имеет возможное значение 4294967296. Допустим, 4 миллиарда для простоты. Вы генерируете 1 миллион случайных целых чисел. Это означает, что каждое из этих случайных целых чисел с вероятностью примерно 1 на 4000 случайным образом имеет то же значение, что и другое. Это немного, но это для одного целого числа, и у вас есть 999999 других случаев для тестирования. Математика, стоящая за этим, немного сложна, но давайте просто скажем, что шансы получить дубликаты почти равны 1/1.

http://en.wikipedia.org/wiki/Birthday_problem

Комментарии:

1. На самом деле, еще в 1980-х годах была написана статья, в которой указывалось, что к моменту выборки 3 * sqrt (RAND_MAX) вероятность увидеть дубликат для случайных чисел будет больше 0,99, и что это можно использовать, чтобы показать, что PRNG, которые использовали свое состояние в качестве выходных данных, не являются случайными. В этом случае 3 * sqrt (2 ^ 32) равно примерно 200_000, поэтому OP обязательно должен увидеть несколько дубликатов, если PRNG хоть сколько-нибудь хорош.

2. это более вероятно, поскольку я использую Math.abs () для результирующего случайного числа, поэтому я получаю только положительные целые числа.