Алгоритм генерации случайного числа

голоса
7

Я ищу, чтобы сгенерировать случайное число и выпустить его в таблицу в базе данных для конкретного user_id. Улов, тот же номер не может быть использован дважды. Там в миллион способов сделать это, но я надеюсь, что кто-то очень сильно на алгоритмах есть умный способ решения проблемы в элегантном решении в том, что следующие критериях:

1) Наименьшее количество запросов к базе данных сделаны. 2) наименьшее количество обхода через структуры данных в памяти производится.

По существу, идея заключается в том, чтобы сделать следующее

1) Создать случайное число от 0 до 9999999
2) Проверьте базу данных , чтобы увидеть , если номер существует
или
2) Запрос к базе данных для всех чисел
3) Смотрите , если возвращаемый результат матчей независимо пришли из БД
4) Если они совпадают, повторите шаг 1, если нет, то проблема решена.

Благодарю.

Задан 26/11/2008 в 02:44
источник пользователем
На других языках...                            


17 ответов

голоса
1

Я думаю, вы обнаружите, что вы действительно не хотите, чтобы это сделать. Поскольку число в увеличении базы данных, вы можете потратить слишком много времени в «Убедитесь, что это число не принято» цикл.

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

Ответил 26/11/2008 в 02:51
источник пользователем

голоса
1

Мой опыт был просто с помощью ГСЧ в PHP. Я обнаружил, что использование определенного размера числа (я использую Int, поэтому у меня есть максимум на 4G). Я провел несколько тестов и обнаружили, что в среднем, в 500000 итераций, я получил 120 одиночных дубликатов. Я никогда не получал Triplicate после запуска Петли кучи раз. Мое «решение» было тогда просто вставить и проверить, если это не удается, то генерировать новый идентификатор и идти снова.

Мой совет, чтобы сделать то же самое и посмотреть, что ваша частота столкновений и с и посмотреть, если это приемлемо для вашего случая.

Это не является оптимальным, так что если у кого-то есть предложения, я смотрю тоже :)

EDIT: Я был ограничен 5 цифр ID ([A-Za-z0-9] {5,5}), тем больше идентификаторов (больше комбинации, несколько столкновений). Md5 из письма почти никогда не конфликтуют, например.

Ответил 26/11/2008 в 02:51
источник пользователем

голоса
17

Нет Ваш алгоритм не является масштабируемым. То, что я делал раньше, чтобы выдавать номера последовательно (+1 каждый раз), а затем передавать их через операцию XOR, чтобы перемешивать биты, таким образом, давая мне, казалось бы, случайные числа. Конечно, они не являются действительно случайными, но они выглядят так, чтобы глаз пользователей.


[Править] Дополнительная информация

Логика этого алгоритма выглядит следующим образом использовать известную последовательность для создания уникальных номеров, а затем вы детерминировано манипулировать ими, так что они не смотрят серийный больше. Общее решение заключается в использовании той или иной форме шифрования, что в моем случае был XOR Триггер, потому что его так быстро, как он может получить, и он выполняет гарантию того, что номера никогда не конфликтуют.

Однако вы можете использовать другие формы шифрования, если вы хотите, предпочитаете даже больше случайные числа выглядящих, над скоростью (скажем, вам не нужно создавать множество идентификаторов в то время). Теперь важный момент в выборе алгоритма шифрования является «гарантией того, что номера никогда не сталкиваются». И способ доказать, если алгоритм шифрования может выполнить эту гарантию, чтобы проверить, как оригинальный номер и результат шифрования имеют одинаковое количество бит, и что алгоритм является обратимой (биекция).

[Благодаря Адам Liss & CesarB для exapanding на решение]

Ответил 26/11/2008 в 02:51
источник пользователем

голоса
1

Проблема заключается в том, что если вы генерации случайных чисел является очень возможно изготовление дубликатов infinatly.

Однако:

<?php
//Lets assume we already have a connection to the db
$sql = "SELECT randField FROM tableName";
$result = mysql_query($sql);
$array = array();
while($row = mysql_fetch_assoc($result))
 {
   $array[] = $row['randField'];
 }
while(True)
 {
   $rand = rand(0, 999999);
   if(!in_array($rand))
     {
       //This number is not in the db so use it!
       break;
     }
 }
?>

В то время как это будет делать то, что вы хотите, это тоже, это плохая идея, так как это не будет масштабироваться долго, eventualy вашего массива будет добраться до большого, и это займет очень много времени, чтобы генерировать случайный, который уже не в вашей БД ,

Ответил 26/11/2008 в 02:55
источник пользователем

голоса
2

Предполагая, что:

  • Случайность необходима уникальность, а не для обеспечения безопасности
  • Ваш user_id 32 бит
  • Ваш предел 9999999 был просто пример

Вы могли бы сделать что-то простое, как имеющие случайное число как 64 битное целое, с верхними 32 битами, содержащих метку времени (в строке вставки) и нижние 32 бит поле user_id. Это было бы уникальным даже для нескольких строк с тем же пользователем, при условии использования соответствующего разрешения на вашем временном метка в зависимости от того, как часто вы добавляете новые строки для одного пользователя. Совместимый с уникальным ограничением на случайной колонке и поймать любую такую ​​ошибку в вашей логике, а затем просто повторить.

Ответил 26/11/2008 в 03:00
источник пользователем

голоса
1

Это легко создать генератор псевдослучайных чисел с длинным периодом nonrepetition; например , это один , который используется для того же , что вы хотите его.

Кстати, почему бы не просто выдавать последовательно в идентах?

Ответил 26/11/2008 в 03:02
источник пользователем

голоса
0

PHP уже имеет функцию для этого, uniqid . Он генерирует стандартный UUID , который является большим , если у вас есть доступ к данным из других источников . Не изобретать колесо.

Ответил 26/11/2008 в 03:06
источник пользователем

голоса
6

Хотите по-топ решение?

Я предполагаю, что случайность не предназначена для шифрования качества, но достаточно, чтобы препятствовать угадать долговечность пользователя, на user_id.

В процессе разработки, создание списка всех 10 миллионов чисел в виде строки.

Необязательно выполнять некоторые простые преобразования, как добавить постоянную строку в середине. (Это только в том случае, результат слишком предсказуем.)

Передайте их в инструмент , который создает совершенные функции Hash , такие как Gperf .

Полученный код может быть использован для быстрого кодирования идентификатора пользователя во время выполнения в уникальный хэш-значение, которое гарантированно не конфликтовать с другими хеш-значения.

Ответил 26/11/2008 в 03:16
источник пользователем

голоса
17

Почему бы вам не просто использовать GUID? Большинство языков должны иметь встроенный способ сделать это. Это гарантировано быть уникальным (с очень разумными пределами).

Ответил 26/11/2008 в 03:19
источник пользователем

голоса
1

Мне нравится идея Oddthinking, но вместо того, чтобы выбирать самую сильную хэш-функцию в мире, вы могли бы просто:

  • Сгенерировать MD5-х первых 10 миллионов чисел (выраженных в виде строк, + немного соли)
  • Проверка дубликатов отсутствует , то есть , прежде чем в производстве (я предполагаю , что там не будет)
  • Храните дубликаты в массив где-то
  • При запуске приложения, загрузите массив
  • Если вы хотите вставить ID, выбрать следующий номер, вычислить его MD5, проверьте, если он находится в массиве, и если она не использовать его в качестве идентификатора в базе данных. В противном случае, выберите следующий номер

MD5 являются быстро, и проверить, если строка принадлежит массиву избежит вам SELECT.

Ответил 26/11/2008 в 03:41
источник пользователем

голоса
3

Попробуйте заявление в тузде SELECT CAST (RAND () * 1000000. AS INT)

Ответил 26/11/2008 в 08:51
источник пользователем

голоса
1

Я на самом деле ранее написал статью об этом . Это тот же подход , как ответ Роберта Гулда, но дополнительно показывает , как сократить блочного шифра до нужной длины с помощью XOR складывание, а затем , как генерировать перестановки в диапазоне , который не является степенью 2, в то же время сохраняя свойство единственности.

Ответил 26/11/2008 в 11:13
источник пользователем

голоса
0

Я, вероятно, не поймать свою точку зрения, но как насчет auto_increments?

Ответил 27/11/2008 в 19:11
источник пользователем

голоса
1

Если вы действительно хотите получить «случайных» чисел формы 0 до 9 999 999, то решение сделать «рандомизации» один раз, а затем сохранить результат на диск.

Это не трудно, чтобы получить результат, который вы хотите, но я думаю об этом больше как «сделать длинный список с номерами», чем «получить случайное число».

$array = range(0, 9999999);
$numbers = shuffle($array);

Кроме того, необходимо указатель текущей позиции в $ чисел (хранить в базе данных); начиная с 0 и увеличивать его каждый раз, когда вам нужен новый номер. (Или вы можете использовать array_shift () или array_pop (), если вы не хотите использовать указатели.)

Ответил 27/11/2008 в 23:41
источник пользователем

голоса
1

Алгоритм собственно ПСЧ (Псевдо-генератор случайных чисел) будет иметь время цикла, в течение которого он никогда не будет в том же состоянии. Если вы подвергаете все состояние PRNG числа, извлеченное из него, вы получите номер гарантированно уникальной для периода генератора.

Простой ПСЧ , который делает это называется « линейный конгруэнтная PRNG» , который итерирует формулу:

X(i) = AX(i-1)|M

Используя правильную пару факторов вы можете получить в период 2 ^ 30 (примерно 1 миллиард) от простого ПСЧ с 32 битным аккумулятором. Обратите внимание, что вам потребуется 64 бит долго долго временной переменной для хранения промежуточного «AX» часть вычислений. Большинство, если не все компиляторы будут поддерживать этот тип данных. Вы также должны быть в состоянии сделать это с числовым типом данных на большинстве диалектов SQL.

С правильными значениями А и М можно получить генератор случайных чисел с хорошими статистическими и геометрическими свойствами. Существует известная статья об этом написано Фишмана и Мур.

Для M = 2 ^ 31 - 1 получает можно использовать значение А ниже, чтобы получить ПСЧ с красивым длинным периодом (2 ^ 30 IIRC).

Хорошие значения A:

742,938,285  
950,706,376  
1,226,874,159  
62,089,911  
1,343,714,438   

Обратите внимание , что этот тип генератора (по определению) не криптографически безопасный. Если вы знаете , последний номер сгенерированный из него вы можете предсказать , что он будет делать дальше. К сожалению , я считаю , что вы не можете получить криптографическую защиту и гарантированную неповторяемость одновременно. Для ПГСЧ быть криптографический безопасным (например , Блюм Блюм Шубы ) он не может выставить достаточное состояние в сгенерированном числе , чтобы позволить следующему номеру в последовательности , чтобы быть предсказан. Поэтому внутреннее состояние шире , чем сгенерированное число и (для того , чтобы иметь хорошую безопасность) период будет больше , чем число возможных значений , которые могут быть сгенерированы. Это означает , что обнаженный номер не будет уникальным в пределах периода.

По тем же причинам , то же самое относится и к длиннопериодических генераторов , таких как Вихрь Мерсенна.

Ответил 27/11/2008 в 23:59
источник пользователем

голоса
1

Есть несколько способов, чтобы идти об этом так бы построить массив с номерами 0000000 через 9999999, а затем выбрать случайный выбор из этих чисел в этом массиве и поменять отборные номера значения с наивысшим значением Max затем уменьшить макс на 1 и выбрать другой случайный элемент этого массива до нового максимума

каждый раз уменьшая Макс один

(например, в основном): (вправо, являются комментариями, которые должны быть удалены в реальной программе) Rndfunc является вызовом функции генератора случайных чисел независимо вы используете

dim array(0 to 9999999) as integer
for x% = 1 to 9999999
array(x%)=x%
next x%
maxPlus = 10000000
max =9999999
pickedrandom =int(Rndfunc*maxPlus)  picks a random indext of the array based on    
                                   how many numbers are left
maxplus = maxplus-1
swap array(pickedrandom) , array(max) swap this array value to the current end of the
                                     array 
max = max -1                   decrement the pointer of the max array value so it 
                              points to the next lowest place..

затем продолжать делать это для каждого номера, который вы хотите выбрать, но вам нужно будет иметь возможность использовать очень большие массивы

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

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

Ответил 27/01/2012 в 14:05
источник пользователем

голоса
0

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

Основная идея заключается в том , что следующая формула seed * seed & pбудет произведена неповторяющимися случайными числа для любого входного сигнала x such that 2x < pи p - x * x % pпроизводит все другие случайные числа как хорошо неповторяющиеся, но только в том случае p = 3 mod 4. Таким образом , в основном все , что вам нужно , это один primnumber как можно ближе к 9999999максимально возможной. Таким образом, усилия могут быть сведены к одной считывающей области, но с другой стороны , что либо слишком большие идентификаторы генерируются или слишком мало идентификаторы будут генерироваться.

Этот алгоритм не переставляет очень хорошо, поэтому я бы рекомендовал его сочетание с любым XOR или того или иным подходом, чтобы изменить точное значение, не разрушая 1-к-1-соотношение между семенами и их сгенерированного значением.

Ответил 04/10/2015 в 22:49
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more