Какова вероятность столкновения с 6-значным случайным буквенно-цифровым кодом?
Я использую следующий код perl для генерации случайных буквенно-цифровых строк (только буквы и цифры в верхнем регистре) для использования в качестве уникальных идентификаторов для записей в моей базе данных MySQL. База данных, вероятно, останется под 1 000 000 строк, но абсолютный реалистичный максимум составит около 3 000 000. Есть ли у меня опасная вероятность того, что 2 записи имеют один и тот же случайный код, или это может произойти незначительно малым числом раз? Я очень мало знаю о вероятности (если это уже не совсем ясно из природы этого вопроса) и будет любить кого-то вводить.
perl -le 'print map { ("A".."Z", 0..9)[rand 36] } 1..6'
Ответы
Ответ 1
Из-за Парадокса День рождения это скорее, чем вы думаете.
Существует 2 176 782 336 возможных кодов, но даже вставка всего 50 000 строк уже имеет довольно высокую вероятность столкновения. Для 1 000 000 строк почти неизбежно, что будет много столкновений (я думаю, около 250 в среднем).
Я провел несколько тестов, и это число кодов, которые я мог бы создать до первого столкновения:
Коллизии будут становиться все более частыми по мере увеличения количества кодов.
Вот мой тестовый код (написанный на Python):
>>> import random
>>> codes = set()
>>> while 1:
code=''.join(random.choice('1234567890qwertyuiopasdfghjklzxcvbnm')for x in range(6))
if code in codes: break
codes.add(code)
>>> len(codes)
36909
Ответ 2
Ну, у вас есть 36 ** 6 возможных кодов, что составляет около 2 миллиардов. Назовите это d. Используя найденную формулу здесь, мы обнаруживаем, что вероятность столкновения для n кодов приблизительно равна
1 - ((d-1)/d)**(n*(n-1)/2)
Для любого n более 50 000 или около того, это довольно высокое.
Похоже, что 10-символьный код имеет вероятность столкновения всего около 1/800. Так что идите с 10 или более.
Ответ 3
Основываясь на уравнениях, приведенных в http://en.wikipedia.org/wiki/Birthday_paradox#Approximation_of_number_of_people, существует 50% вероятность столкновения хотя бы с одним столкновением после вставки только 55 000 записей или поэтому во вселенную такого размера:
http://wolfr.am/niaHIF
Попытка вставить в два-шесть раз больше записей почти наверняка приведет к столкновению. Вам необходимо назначить коды неслучайно или использовать более крупный код.
Ответ 4
Как упоминалось ранее, парадокс дня рождения делает это событие вполне вероятным. В частности, точная аппроксимация может быть определена, когда задача задана как проблема столкновения. Пусть p(n; d)
- вероятность того, что по крайней мере два числа одинаковы, d
- количество комбинаций и n
количество трасс. Тогда мы можем показать, что p(n; d)
приблизительно равно:
1 - ((d-1)/d)^(n*(n-1)/2)
Мы можем легко построить это в R:
> d = 2176782336
> n = 1:100000
> plot(n,1 - ((d-1)/d)^(n*(n-1)/2), type='l')
который дает
![enter image description here]()
Как вы можете видеть, вероятность столкновения очень быстро возрастает с количеством проб/строк
Ответ 5
Пока я не знаю специфики того, как вы хотите использовать эти псевдослучайные идентификаторы, вы можете захотеть создать массив из 3000000 целых чисел (от 1 до 3000000) и случайным образом перетасовать его. Это гарантирует, что номера уникальны.
См. Фишер-Йейтс перетасовывается в Википедии.
Ответ 6
Предупреждение: Остерегайтесь полагаться на встроенный rand
, где важно качество генератора псевдослучайных чисел. Недавно я узнал о Math:: Random:: MT:: Auto:
Mersenne Twister - это быстрый генератор псевдослучайных чисел (PRNG), способный предоставлять большие объемы ( > 10 ^ 6004) псевдослучайных данных высокого качества для приложений, которые могут исчерпывать доступные "по-настоящему" источники случайных данных или системные данные, предоставляемые PRNG, такие как rand
.
Модуль обеспечивает сокращение замены rand
, которое удобно.
Вы можете сгенерировать последовательность клавиш со следующим кодом:
#!/usr/bin/env perl
use warnings; use strict;
use Math::Random::MT::Auto qw( rand );
my $SEQUENCE_LENGTH = 1_000_000;
my %dict;
my $picks;
for my $i (1 .. $SEQUENCE_LENGTH) {
my $pick = pick_one();
$picks += 1;
redo if exists $dict{ $pick };
$dict{ $pick } = undef;
}
printf "Generated %d keys with %d picks\n", scalar keys %dict, $picks;
sub pick_one {
join '', map { ("A".."Z", 0..9)[rand 36] } 1..6;
}
Некоторое время назад я писал о ограниченном диапазоне встроенных rand
в Windows. Возможно, вы не находитесь в Windows, но в вашей системе могут быть другие ограничения или ошибки.