#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.
Комментарии:
1. На самом деле, еще в 1980-х годах была написана статья, в которой указывалось, что к моменту выборки 3 * sqrt (RAND_MAX) вероятность увидеть дубликат для случайных чисел будет больше 0,99, и что это можно использовать, чтобы показать, что PRNG, которые использовали свое состояние в качестве выходных данных, не являются случайными. В этом случае 3 * sqrt (2 ^ 32) равно примерно 200_000, поэтому OP обязательно должен увидеть несколько дубликатов, если PRNG хоть сколько-нибудь хорош.
2. это более вероятно, поскольку я использую Math.abs () для результирующего случайного числа, поэтому я получаю только положительные целые числа.