Algorytm generowania liczb losowych

głosy
7

Szukam do generowania liczb losowych i wydać go na stole w bazie danych dla danego user_id. Haczyk jest ta sama liczba nie może być stosowany dwa razy. Jest milion sposobów, aby to zrobić, ale mam nadzieję, że ktoś bardzo zależało na algorytmach ma sprytny sposób rozwiązania problemu w eleganckie rozwiązanie, że poniższe kryteria są spełnione:

1) co najmniej ilość zapytań do bazy danych są wykonane. 2) co najmniej ilość indeksowania przez strukturę danych w pamięci jest.

Zasadniczo chodzi o to, aby wykonać następujące czynności

1) Utwórz liczbę losową z zakresu od 0 do 9999999
2) Sprawdź bazę, aby zobaczyć, czy numer istnieje
LUB
2) zapytanie do bazy danych dla wszystkich liczb
3) Sprawdź, czy powracające mecze wynik cokolwiek pochodzi od db
4) jeżeli to pasuje, powtórz etap 1, jeśli nie, to problem jest rozwiązany.

Dzięki.

Utwórz 26/11/2008 o 02:44
źródło użytkownik
W innych językach...                            


17 odpowiedzi

głosy
1

Myślę, że przekonasz się, że naprawdę nie chce tego robić. Jak numery na wzrost bazy danych, może spędzać zbyt dużo czasu w „Upewnij się, liczba ta nie jest brany” pętli.

Osobiście miałem szczęście z mieszań jako alternatywa, ale wymyślić lepszego rozwiązania, będę naprawdę trzeba wiedzieć, dlaczego chcesz to zrobić w ten sposób.

Odpowiedział 26/11/2008 o 02:51
źródło użytkownik

głosy
1

Moje doświadczenie było po prostu za pomocą RNG w PHP. Okazało się, że za pomocą pewnej liczby wielkości (używam int, więc mam max 4G). Pobiegłem jakieś testy i okazało się, że średnio w 500000 iteracji, mam 120 pojedynczych duplikatów. Nigdy nie dostał sześcianem po uruchomieniu pętli kilka razy. Mój „rozwiązanie” było wtedy wystarczy włożyć i sprawdzić, czy nie, a następnie wygenerować nowy identyfikator i znowu.

Moja rada jest, aby zrobić to samo i zobaczyć, co jest stawka kolizji & c i sprawdzić, czy jest to dopuszczalne dla sprawy.

To nie jest optymalna, więc jeśli ktoś ma sugestie szukam też :)

Edycja: ograniczono do ID 5 cyfrowym ([a-za-Z0-9] {5,5}), przy czym dłuższe id (więcej kombinacji, kilka kolizji). Md5 wiadomości e-mail nigdy prawie sprzeczności, na przykład.

Odpowiedział 26/11/2008 o 02:51
źródło użytkownik

głosy
17

Nie Twój algorytm nie jest skalowalne. Co robiłem zanim jest wydawanie numerów seryjnych (+1 za każdym razem), a następnie przekazać je poprzez operację XOR na jumble bity dając mi pozornie liczb losowych. Oczywiście, że tak naprawdę nie są przypadkowe, ale wyglądają tak na oczach użytkowników.


[Edytuj] Informacje dodatkowe

logika tego algorytmu idzie tak użyć znaną sekwencję do generowania unikalnych numerów i wtedy deterministycznie nimi manipulować, więc nie wyglądają już seryjny. Ogólnym rozwiązaniem jest zastosowanie jakiejś formy szyfrowania, co w moim przypadku było flipflop XOR, bo jej tak szybko, jak można go dostać, i spełnia ona gwarancję, że numery nigdy nie zderzają.

Można jednak korzystać z innych form szyfrowania, jeśli chcesz wolą bardziej losowe wyglądających liczb, nad prędkością (powiedzmy nie trzeba generować wiele identyfikatorów naraz). Teraz ważny punkt w wyborze algorytmu szyfrowania jest „gwarancja, że ​​numery nie będą kolidować”. I sposób udowodnić, jeśli algorytm szyfrowania może spełnić tej gwarancji jest sprawdzenie, czy zarówno oryginalny numer i wynik szyfrowania mają taką samą liczbę bitów, i że algorytm jest odwracalna (bijection).

[Dzięki Adam Liss i CesarB do exapanding w roztworze]

Odpowiedział 26/11/2008 o 02:51
źródło użytkownik

głosy
1

Problemem jest to, że jeśli jesteś generowania liczb losowych jest bardzo możliwe wytwarzanie duplikatów infinatly.

jednak:

<?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;
     }
 }
?>

O ile będzie to robić co chcesz go też, że jest to zły pomysł, bo nie będzie to skala na długo, eventualy macierzy dostanie się duża i zajmie bardzo dużo czasu, aby wygenerować losowy, który nie jest już w db ,

Odpowiedział 26/11/2008 o 02:55
źródło użytkownik

głosy
2

Zarozumiały:

  • Losowość jest potrzebne do wyjątkowości, nie dla bezpieczeństwa
  • Twój user_id jest 32-bitowy
  • Twój limit 9999999 był tylko przykład

Można to zrobić w prosty co o losową liczbę jako 64 bitową liczbę całkowitą, przy czym górne 32 bitów zawierających znacznik czasu (na wkładce za drugim) i dolnych 32 Bity IDENTYFIKATOR_UŻYTKOWNIKA. To byłby wyjątkowy nawet dla wielu wierszy z tego samego użytkownika, pod warunkiem korzystania stosowną uchwałę na datownik w zależności od tego, jak często dodawać nowe wiersze dla tego samego użytkownika. W połączeniu z unikalnym przymusu na kolumnie losowej i złapać takiego błędu w swojej logice, a następnie po prostu ponownie.

Odpowiedział 26/11/2008 o 03:00
źródło użytkownik

głosy
1

Łatwo jest zaprojektować generator liczb pseudolosowych o długim okresie nonrepetition; na przykład ten , który jest używany do tej samej rzeczy, które chcesz go.

BTW, dlaczego po prostu nie wydać kolejno identyfikator użytkownika jest?

Odpowiedział 26/11/2008 o 03:02
źródło użytkownik

głosy
0

PHP ma już funkcję dla tego, uniqid . Generuje standardową UUID, które jest świetne, jeśli masz dostęp do danych z innych źródeł. Nie wyważać otwartych drzwi.

Odpowiedział 26/11/2008 o 03:06
źródło użytkownik

głosy
6

Chcesz over-the-top rozwiązanie?

Zakładam losowość nie jest przeznaczony do szyfrowania jakości, ale wystarczy, aby zniechęcić do zgadywania długowieczność użytkownikiem za user_id.

Podczas rozwoju wygenerować listę wszystkich 10 milionów numerów w postaci łańcucha.

Ewentualnie wykonać kilka prostych transformacji, jak dodanie stałej ciąg na środku. (To jest tylko w przypadku, gdy wynik jest zbyt przewidywalne.)

Przekazać je w narzędzie, które generuje Perfekcyjne funkcje skrótu , takie jak gperf .

Otrzymany kod może być użyty do szybkiego kodowania identyfikatora użytkownika w czasie wykonywania w wyjątkowej wartości hash, która jest zagwarantowana, aby nie kolidować z wszelkich innych wartości hash.

Odpowiedział 26/11/2008 o 03:16
źródło użytkownik

głosy
17

Dlaczego nie można po prostu użyć GUID? Większość języków powinien mieć wbudowany sposób to zrobić. To muszą być unikalne (z bardzo rozsądnych granicach).

Odpowiedział 26/11/2008 o 03:19
źródło użytkownik

głosy
1

Lubię pomysł Oddthinking, ale zamiast wyboru najsilniejszego funkcji skrótu w świecie, można po prostu:

  • Generowanie MD5 użytkownika z pierwszych 10 milionów numerów (wyrażonych jako ciągi + trochę soli)
  • Sprawdzić duplikatów nieaktywny , czyli przed udaniem się w produkcji (myślę, że nie będzie w ogóle)
  • Przechowywanie duplikatów w tablicy gdzieś
  • Po uruchomieniu aplikacji, załadować tablicę
  • Gdy chcesz wstawić identyfikator, wybrać następny numer, obliczyć swoją MD5, sprawdź, czy jest w tablicy, a jeśli nie jest go używać jako ID w bazie danych. W przeciwnym razie wybierz następny numer

MD5 są szybkie, i sprawdzenie czy ciąg należy do tablicy pozwoli uniknąć Ci SELECT.

Odpowiedział 26/11/2008 o 03:41
źródło użytkownik

głosy
3

Spróbuj oświadczenie mysql SELECT CAST (RAND () * 1000000 int)

Odpowiedział 26/11/2008 o 08:51
źródło użytkownik

głosy
1

Ja faktycznie wcześniej napisany artykuł na ten temat . To zajmuje takie samo podejście jak odpowiedź Roberta Goulda, ale dodatkowo pokazuje, jak skrócić szyfr blokowy do odpowiedniej długości za pomocą xor składanie, a następnie w jaki sposób do generowania permutacji w pewnym zakresie, który nie jest potęgą 2, przy jednoczesnym zachowaniu właściwość wyjątkowości.

Odpowiedział 26/11/2008 o 11:13
źródło użytkownik

głosy
0

I prawdopodobnie nie złapać swój punkt, ale co auto_increments?

Odpowiedział 27/11/2008 o 19:11
źródło użytkownik

głosy
1

Jeśli naprawdę chcesz, aby „Random” numery formularza 0 do 9 999 999, wówczas rozwiązaniem jest zrobić „randomizacji” raz, a następnie zapisać wynik na dysku.

To nie jest trudne, aby uzyskać wynik, który chcesz, ale myślę o nim bardziej jak „zrobić długą listę z numerami”, niż „dostać liczbę losową”.

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

Musisz również wskaźnik do aktualnej pozycji w $ liczb (przechowywać je w bazie danych); zaczynają się od 0 i zwiększać za każdym razem trzeba nowy numer. (Lub można użyć array_shift () lub array_pop (), jeśli nie chcesz używać wskaźników).

Odpowiedział 27/11/2008 o 23:41
źródło użytkownik

głosy
1

Algorytm właściwa PRNG (Pseudo-Random Number Generator) będzie miał czas cyklu, podczas którego nigdy nie będzie w takim samym stanie. Jeśli odsłonić całą stan PRNG w ilości pobranej od niego, otrzymasz unikalny numer gwarantowane przez okres generatora.

Prosty PRNG że robi to nazywane jest „ normalny przystający PRNG”, które wykonuje iteracje wzoru:

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

Stosując odpowiednią parę czynników można dostać okres 2 ^ 30 (około 1 mld euro) od prostego PRNG z 32 bitowym akumulatorze. Należy pamiętać, że trzeba będzie 64 bit long long zmienną tymczasową trzymać pośrednią „AX” część obliczeń. Większość, jeśli nie wszystkie kompilatory C będzie wspierać ten typ danych. Należy również być w stanie to zrobić z liczbowym typem danych w większości dialektów SQL.

Z odpowiednimi wartościami A i M możemy uzyskać generator liczb losowych o dobrych właściwościach statystycznych i geometrycznych. Jest znanym papier o tym napisane przez Fishman i Moore'a.

Dla M = 2 ^ 31 - 1 otrzymujemy mogą korzystać z wartościami poniżej, aby uzyskać PRNG z ładnym długim okresie (2 ^ 30 IIRC).

Dobrymi wartościami:

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

Zauważ, że ten rodzaj generatora jest (z definicji) nie kryptograficznie bezpieczne. Jeśli wiesz, ostatni numer wygenerowany z niego można przewidzieć, co będzie robić dalej. Niestety uważam, że nie można dostać bezpieczeństwo kryptograficzne i gwarantowaną niepowtarzalność w tym samym czasie. Dla PRNG być kryptograficznie bezpieczny (np Blum Blum Shub ) nie może wystawiać wystarczający stan w wygenerowanej liczby, aby umożliwić następny numer w kolejności należy przewidzieć. Dlatego stan wewnętrzny jest szerszy niż generowanym numerem oraz (aby mieć dobre zabezpieczenie) okres będzie dłuższy niż liczba możliwych wartości, które mogą być generowane. Oznacza to, że liczba ekspozycji nie będzie wyjątkowy w terminie.

Z podobnych powodów, tak samo jest z generatorów długookresowe, takie jak Mersenne Twister.

Odpowiedział 27/11/2008 o 23:59
źródło użytkownik

głosy
1

istnieje kilka sposobów, aby przejść o jeden sposób byłoby skonstruować tablicę z numerami 0000000 poprzez 9999999, a następnie wybrać losowo wybierać z tych numerów w tej tablicy i zamienić pobrane wartości liczb o najwyższej wartości Max następnie zmniejszyć max przez 1 i wybrać inną losową członek tej tablicy do nowego maksimum

za każdym razem zmniejszając Max przez jednego

na przykład (w podstawowy): (po prawej stronie są komentarze, które powinny zostać usunięte w rzeczywistym programu) Rndfunc jest wezwaniem do tego, co generatora liczb losowych funkcją używasz

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..

następnie dalej robić to dla każdego numeru, który chcesz wybrać, ale trzeba będzie mieć możliwość korzystania z bardzo dużych tablic

druga metoda będzie w następujący sposób: wygenerować numer i przechowywać go do tablicy, które mogą rozwijać się dynamicznie następnie potem wybrać nowy numer, a następnie porównać ją z wartością, która jest w połowie drogi od pierwszego do ostatniego elementu w tablicy w tym przypadku byłby to pierwszy numer wybrał jeśli pasuje wybrać inną liczbę losową, posortować tablicę według wielkości, a jeśli nie ma odpowiednika następnie w zależności od pogody jest większa lub mniejsza od liczby ty porównaniu go ze idziesz w górę lub w dół lista połowa połowy odległości, za każdym razem, że to nie pasuje i jest większa lub mniejsza niż to, co ty porównujesz go.

każdorazowo połowę go aż do osiągnięcia wielkości szczeliny jednego następnie sprawdzić raz i zatrzymać jak nie ma mecz, a potem numer telefonu zostanie dodany do listy, a lista jest przetasowanie w porządku rosnącym, tak dalej i tak dalej, dopóki nie są zrobić zbierając liczb losowych ... mam nadzieję, że to pomoże ..

Odpowiedział 27/01/2012 o 14:05
źródło użytkownik

głosy
0

Jeśli chcesz się upewnić, że numery losowych nie powtarzają, trzeba non-powtórzenie losowy numer generatora (jak opisano tutaj ).

Podstawowym założeniem jest to, że następująca formuła seed * seed & pbędzie produkowany non-powtórzenie losowych liczb dla każdego wejścia x such that 2x < pi p - x * x % pprodukuje wszystkie inne liczb losowych aswell non-powtórzenie, ale tylko wtedy p = 3 mod 4. Więc w zasadzie wszystko, co potrzebne jest jedno primnumber tak blisko 9999999jak to możliwe. W ten sposób wysiłek może być zmniejszona do jednego pola odczytu, ale z drugiej jednak strony, że albo zbyt duże identyfikatory są generowane lub zostanie wygenerowany za mało identyfikatory.

Ten algorytm nie permutacji bardzo dobrze, więc polecam łącząc ją z obu XOR lub dodanie lub innego podejścia do zmian dokładną wartość bez niszczenia 1-do-1-relację między nasionami i ich generowanej wartości.

Odpowiedział 04/10/2015 o 22:49
źródło użytkownik

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