Rasgele bir sayı üretmek için algoritma

15 Cevap php

Ben rastgele bir sayı oluşturmak ve belirli bir user_id için bir veritabanındaki bir tabloya vermek için arıyorum. Yakalamak, aynı numara iki kez kullanılamaz, olduğunu. Orada bunu yapmak için bir milyon yolu var, ama ben algoritmaları çok düşkün birisi bir akıllı olduğunu aşağıdaki kriterlere şık bir çözelti içinde problem çözme yolu karşılanmaktadır vardır umuyorum:

1) The least amount of queries to the database are made. 2) The least amount of crawling through a data structure in memory is made.

Esasen fikir aşağıdaki yapmaktır

1) Create a random number from 0 to 9999999
2) Check the database to see if the number exists
OR
2) Query the database for all numbers
3) See if the returned result matches whatever came from the db
4) If it matches, repeat step 1, if not, problem is solved.

Teşekkürler.

15 Cevap

Hayır senin algoritma ölçeklenebilir değildir. Ne daha önce yaptığım seri numaralarını vermek (1 her zaman) ve sonra bu şekilde bana bir rastgele numaralarını vererek bit karmakarışık bir XOR ile onlara geçmektir. Tabii ki onlar gerçekten rastgele değil, ancak kullanıcıların gözlere çok görünüyorsun.


[Edit] Ek bilgi

This algorithm's logic goes like this you use a known sequence to generate unique numbers and then you deterministically manipulate them, so they don't look serial anymore. The general solution is to use some form of encryption, which in my case was an XOR flipflop, because its as fast as it can get, and it fulfills the guarantee that numbers will never collide.

However you can use other forms of encryption, if you want prefer even more random looking numbers, over speed (say you don't need to generate many ids at a time). Now the important point in choosing an encryption algorithm is "the guarantee that numbers will never collide". And a way to prove if an encryption algorithm can fulfill this guarantee is to check if both the original number and the result of the encryption have the same number of bits, and that the the algorithm is reversible (bijection).

[Sayesinde Adam Liss & CesarB çözüm exapanding için]

Neden sadece bir GUID kullanmak değil mi? Çoğu dilde bu yapmak için yerleşik bir yol olmalıdır. O (çok makul sınırlar ile) benzersiz olmasını garanti ediyor.

Bir over-the-top bir çözüm istiyor?

Ben rastgele şifreleme kaliteli olması amaçlanmıştır, ancak user_id tarafından bir kullanıcının uzun ömürlü, tahmin vazgeçirmek için yeterli değildir varsayıyorum.

Gelişimi sırasında, string şeklinde tüm 10 milyon numaralarının bir listesini oluşturmak.

İsteğe bağlı olarak, ortada sabit bir dize ekleyerek gibi, bazı basit dönüşümü gerçekleştirmek. (Bu sonuç çok öngörülebilir sadece durumda olduğunu.)

Böyle gperf olarak, Perfect Hash functions üreten bir araç haline onları geçmek.

Oluşan kod hızlı başka bir hash değerleri ile çatışma değil garanti benzersiz bir karma değer haline kullanıcının kimliği zamanında kodlamak için kullanılır.

Varsayarsak:

  • Rasgelelik teklik için değil, güvenlik için gerekli
  • Sizin User_id 32 bit
  • 9999999 Sizin limiti sadece bir örnek oldu

You could do something simple as having the random number as a 64 bit integer, with the upper 32 bits containing the timestamp (at row insert) and the lower 32 bits the user_id. That would be unique even for multiple rows with the same user, provided you use an appropriate resolution on your timestamp depending on how often you add new rows for the same user. Combine with an unique constraint on the random column and catch any such error in your logic and then just retry.

Ben size gerçekten bunu yapmak istemiyorum bulacaksınız düşünüyorum. Veritabanı artış numaraları gibi, "emin olun bu sayı alınmaz" döngü içinde çok fazla zaman harcamak olabilir.

Şahsen ben bir alternatif olarak karmaları ile şans yaşadım, ama daha iyi bir çözüm ile gelip, ben gerçekten bunu bu şekilde yapmak istiyorum neden bilmek gerekiyordu.

Benim deneyim sadece PHP RNG kullanıyordum. Ben sayısının belli bir boyutunu kullanarak (ben bir int kullanıyorum, bu yüzden 4G bir max var) bulundu. Bazı testler yaptım ve ortalama 500.000 yineleme, ben 120 tek çiftleri var olduğunu buldu. Ben döngü bir demet kez çalıştırdıktan sonra üç kopya var asla. Benim "çözüm" sonra sadece takın ve eğer başarısız kontrol edin, sonra yeni bir kimlik oluşturmak ve tekrar gitmek oldu.

Benim tavsiyem aynı yapmak ve çarpışma hızı ve c ne olduğunu görmek ve bu dava için kabul edilebilir olup olmadığını görmek için.

Bu iyi değil, bu yüzden herkes bir öneriniz varsa ben de arıyorum :)

EDIT: Ben 5 haneli bir kimliği ile sınırlı idi ([a-Za-z0-9] {5,5}), uzun kimliği (daha fazla kombinasyon, birkaç çarpışmalar). E-postanın bir md5 örneğin, çelişebilir neredeyse asla.

Sorun rastgele sayılar üreten olup eğer infinatly çiftleri üretmek çok mümkün olmasıdır.

Ancak:

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

Bu çok istiyorum ne yapacak olsa da, bu uzun ölçekli olmayacak gibi kötü bir fikir olduğunu, eventualy diziniz büyük alacak ve sizin db zaten olmadığını rastgele oluşturmak için son derece uzun bir zaman alacak .

Bu tekrarlanmamasını uzun bir süre ile bir rastgele sayı üreteci tasarımı kolay; örneğin this one, hangi için istediğiniz aynı şey için kullanılıyor.

BTW, neden sadece UserID en sırayla veremiyor?

Ben Oddthinking fikrini seviyorum, ama bunun yerine dünyanın en güçlü hash fonksiyonu seçme, sadece olabilir:

  • MD5 en numaralarının ilk 10 milyonlarca (dizeleri olarak ifade + biraz tuz) oluşturun
  • Çiftleri kontrol offline, yani üretim gitmeden önce (sanırım hiç olmayacak)
  • Bir yerde bir dizi çiftleri saklayın
  • Uygulama başladığında, dizi yüklenemedi
  • Eğer bir kimlik eklemek istediğinizde, bir sonraki numarayı seçin onun MD5 hesaplamak, bu dizide olup olmadığını kontrol edin ve eğer değilse veritabanında ID olarak kullanabilirsiniz. Aksi takdirde, sonraki sayıyı seçin

MD5 en hızlı, ve bir dize bir diziye aitse kontrol size SEÇ önlemek olacaktır.

Eğer gerçekten 9 999 999 "rastgele" numaralar formu 0 almak istiyorsanız, o zaman çözüm zamanlar "randomizasyon" yapmak ve sonra diskinize sonucu saklamaktır.

"Rastgele bir sayı olsun" yerine, istediğiniz sonucu elde etmek zor değil, ama ben daha çok "numaraları ile uzun bir listesini yapmak" gibi düşünüyorum.

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

Ayrıca $ numaraları mevcut konumda (bir veritabanında saklamak) için bir işaretçi gerekir; 0 ile başlar ve ona yeni bir numara gerek her zaman artırmak. (Eğer işaretçileri kullanmak için sevmiyorum Yoksa,) ((array_shift kullanmayın) veya array_pop olabilir.)

Uygun bir PRNG (Pseudo-Random Number Generator) algoritma aynı durumda olmayacak sırasında bir döngü zaman var olacaktır. Ondan alınan sayısındaki PRNG tüm devlet maruz ise, jeneratör bir süre için benzersiz garantili bir dizi alacak.

Bu formül dolaşır 'Linear Congruential' PRNG denir gelmez basit PRNG:

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

Eğer (yaklaşık 1 milyar dolar) 32 bit akümülatör ile basit bir PRNG 2 ^ 30 bir süre alabilirsiniz faktörlerin sağ çifti kullanma. Eğer hesaplama ara 'AX' kısmını tutmak için uzun bir geçici değişken bir 64 bit gerekir unutmayın. Çoğu değil tüm C derleyicileri bu veri türünü destekleyen eğer. Ayrıca çoğu SQL lehçeleri üzerine bir sayısal veri türü ile bunu yapmak mümkün olmalıdır.

A ve M doğru değerler ile biz iyi istatistik ve geometrik özelliklere sahip bir rasgele sayı üreteci alabilirsiniz. Fishman ve Moore tarafından yazılmış bu konuda ünlü bir kağıt var.

M = 2 ^ 31 - için biz olsun 1 güzel bir uzun süre (2 ^ 30 IIRC) ile bir PRNG almak için aşağıdaki A değerlerini kullanabilirsiniz.

A İyi Değerler:

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

Jeneratörün bu tür (tanımı gereği) kriptografik olarak güvenli olmadığını not edin. Ondan üretilen son numarasını biliyorsanız bunu bir sonraki ne yapacağını tahmin edebilirsiniz. Ne yazık ki aynı zamanda kriptografik güvenlik ve garantili olmayan tekrarlanabilirlikten alınamıyor inanıyorum. Bir PRNG kriptografik olarak güvenli olması için (örneğin, Blum Blum Shub) bu sırayla sonraki sayı tahmin izin vermek için oluşturulan yeterli sayıda devlet maruz olamaz. Bu nedenle iç durum oluşturulan sayısından daha geniştir ve (iyi güvenlik için) dönem oluşturulabilir olası değerleri sayısından daha uzun olacaktır. Bu açıkta kalan sayısı, dönem içinde benzersiz olması anlamına gelir.

Benzer nedenlerle aynı tür Mersenne Twister. olarak uzun süre jeneratörler doğrudur

Ben aslında daha önce yazdım an article about this. Hala korurken, 2 güç olmayan bir aralıkta permütasyon oluşturmak için nasıl sonra Robert Gould'un cevap olarak aynı yaklaşım, ama ayrıca xor katlama kullanarak, uygun bir uzunlukta bir blok şifreleme kısaltmak için nasıl gösterir ve teklik özelliği.

there are a couple ways to go about this one way would be to construct an array with the numbers 0000000 through 9999999 and then pick a random pick of these numbers in this array and swap the picked numbers values with the highest value Max then reduce max by 1 and pick another random member of this array up to the new maximum

tek En azaltılması her zaman

for example (in basic) : (to the right are comments which should be removed in the actual program) Rndfunc is a call to whatever random number generator function you are using

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

daha sonra almak istediğiniz her numara için bunu yapmaya devam, ancak çok büyük dizileri kullanarak seçeneği olması gerekir

the other method would be as follows :generate a number and store it into an array that can grow dynamically then after that pick a new number and compare it to the value that is halfway from the first to the last element in the array in this case it would be the first number picked if it matches pick another random number, sort the array according to size and if there is not a match then depending on weather it is greater or smaller than the number you compared it with you go up or down in the list half of half the distance, each time that it does not match and is greater or lesser than what you are comparing it to.

Eğer biri bir boşluk boyutuna ulaşana kadar her zaman kadar sonra bir kez kontrol ve hiçbir maç olduğu gibi duracak ve daha sonra sayı listesi ve liste böylece ve böylece, artan sırayla kabineye ilave edilir onu yarıya rasgele sayılar toplama yapılır ... Bu yardımcı olur umarım ..

PHP zaten bunun için bir işlevi vardır, uniqid. Bu başka bir yerden veri erişim varsa büyük bir standart UUID üretir. Tekerleği yeniden icat etmeyin.

Ben muhtemelen noktayı yakalamak, ama ne auto_increments değil mi?