rasgele bir sayı üretmek için bir algoritma

oy
7

Ben rastgele bir sayı oluşturmak ve belirli bir user_id için veritabanındaki bir tabloya yayınlamayı arıyorum. yakalamak, aynı sayıda iki kez kullanılamaz edilir. Orada bunu yapmak için milyonlarca yol, ama algoritmaları üzerinde çok hevesli birisi karşılanmasını aşağıdaki kriterlere bulunan zarif bir çözeltide problem çözme zeki bir yolu vardır umuyorum:

1) veritabanına sorgu en az miktarda yapılır. 2) belleğindeki bir veri yapısı ile tarama en az miktarda yapılır.

Esasen fikri aşağıdakileri yapmaktır

1) 9999999 0'dan rastgele bir sayı oluşturma
) 2 sayı olup olmadığını görmek için veritabanını kontrol
VEYA
2) tüm numaralar için veritabanı sorgulama
3) Bkz eğer db geldi ne olursa olsun iade sonuç maçları
o tekrarını eşleşirse 4) 1. adım, değilse sorun çözüldü.

Teşekkürler.

Oluştur 26/11/2008 saat 02:44
kaynak kullanıcı
Diğer dillerde...                            


17 cevaplar

oy
1

Ben size gerçekten yapmak istemiyorum bulacağınızı düşünüyoruz. Veritabanı artış sayılar gibi, "bu sayı alınmaz emin olun" döngüde çok fazla zaman ayırmanız gerekebilir.

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

Cevap 26/11/2008 saat 02:51
kaynak kullanıcı

oy
1

Benim deneyim sadece PHP RNG kullanıyordu. Ben sayının belirli bir boyuta kullanarak (ben bir int kullanıyorum, bu yüzden 4G bir max var) olduğunu gördük. Bazı testler yaptım ve ortalama olarak 500.000 iterasyonlarında, ben 120 tek çiftleri var olduğunu gördük. Ben döngü bir kaç kez çalıştırdıktan sonra bir üç kopya olmadı. Benim "çözüm" o zaman sadece takın ve başarısız olursa, o zaman yeni bir kimlik oluşturmak ve tekrar gitmek kontrol etmek oldu.

Benim tavsiyem aynı şeyi ve çarpışma oranı & c görebilmesi ve daha dava için kabul edilebilir olup olmadığını görmektir.

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

DÜZENLEME: 5 rakamlı numarası ([a-z-0-9] {5,5}), daha uzun kimliği (daha fazlası kombinasyon halinde, bir kaç çakışma) ile sınırlıydı. e-postanın bir md5 neredeyse örneğin çakışabilir asla.

Cevap 26/11/2008 saat 02:51
kaynak kullanıcı

oy
17

Hayır senin algoritma ölçeklenebilir değildir. Ne önce yaptığım seri numaralarını vermek (1 her zaman) ve daha sonra bu şekilde bana görünüşte rasgele sayılar vererek bitleri karışmak için bir XOR işlemi yoluyla geçmektir. Tabii onlar gerçekten rastgele değil, ancak kullanıcıların gözlere böylece bakmak.


[Düzenle] Ek bilgiler

Bu benzersiz sayılar üretmek için bilinen bir diziyi kullanmak ve sonra deterministically onları manipüle, dolayısıyla artık seri görünmüyor gibi bu algoritmanın mantığı gider. onun kadar hızlı olarak alabilirsiniz ve bu numaralar çarpışır asla garanti yerine getirir, çünkü genel çözümü, benim durumumda bir XOR flipflop oldu şifreleme çeşit kullanmaktır.

Hatta daha rastgele görünümlü numaralar tercih istiyorsanız ancak aşırı hız, şifreleme diğer formları kullanabilirsiniz (bir anda birçok kimlikleri üretmek gerekmez derler). Şimdi bir şifreleme algoritması seçiminde önemli nokta "sayılar çarpışır asla garanti" dir. Ve bu garantiyi yerine getirebilecek bir şifreleme algoritması orijinal numarası ve şifreleme sonuç her iki bit aynı sayıda olmadığını kontrol etmek ise bir yol kanıtlamak için, ve algoritma geri dönüşümlü (bijection) olduğunu.

[Sayesinde Adam Liss ve CesarB çözeltisi ile exapanding için]

Cevap 26/11/2008 saat 02:51
kaynak kullanıcı

oy
1

Sorun rasgele sayılar üreten eğer infinatly çiftleri üretmek için son derece mümkün olduğunu 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 Senin de istediğini yapacak olsa da, bu kadar kötü bir fikir eventualy diziniz büyük alacak, uzun süre ölçek olmayacak ve rastgele senin db önceden bulunmadığından üretmek için son derece uzun zaman alacak olan .

Cevap 26/11/2008 saat 02:55
kaynak kullanıcı

oy
2

varsayarsak:

  • rasgelelik güvenlik için, teklik değil tabi
  • Kişisel user_id 32 bit
  • 9999999 Sizin limiti sadece bir örnekti

Eğer (satır insert) zaman damgası içeren üst 32 bit ve alt 32 bit user_id ile 64 bit tamsayı olarak rastgele sayı sahip olarak basit bir şey yapmak olabilir. Yani aynı kullanıcı için yeni satırlar eklemek ne sıklıkta bağlı olarak zaman damgası üzerinde uygun bir çözünürlük kullanmanız koşuluyla, hatta aynı kullanıcı ile birden fazla satır için benzersiz olacaktır. rasgele sütun üzerinde benzersiz bir kısıtlama ile birleştirin ve mantığında böyle bir hatayı yakalamak ve sonra sadece yeniden deneyin.

Cevap 26/11/2008 saat 03:00
kaynak kullanıcı

oy
1

Bu tekrar yaşanmamalarının uzun bir süre ile, bir rastgele sayı üreteci tasarımı kolaydır; örneğin bu bir sen için istiyorum aynı şey için kullanılıyor.

BTW, neden sadece kullanıcıkimliği en sırayla sorunu?

Cevap 26/11/2008 saat 03:02
kaynak kullanıcı

oy
0

PHP zaten bunun için bir işlevi vardır uniqid . Bu başka bir yerden verilere erişmek için varsa büyük olduğu standart bir uuid üretir. Tekerleği yeniden icat etmeyin.

Cevap 26/11/2008 saat 03:06
kaynak kullanıcı

oy
6

over-the-üst çözüm ister misiniz?

Ben rasgelelik şifreleme kaliteli, ama user_id tarafından, bir kullanıcının ömrünü tahmin vazgeçirmek için yeterli olması amaçlanmamıştır varsayalım.

gelişme sırasında, dize formdaki tüm 10 milyon numaralarının bir listesini oluşturur.

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

Üreten bir aracın içine geçirin Mükemmel Hash fonksiyonları gibi gperf .

Ortaya çıkan kod hızlı başka hash değerleri ile çatışma değil garanti benzersiz karma değer haline zamanında kullanıcının kimliğini kodlamak için kullanılabilir.

Cevap 26/11/2008 saat 03:16
kaynak kullanıcı

oy
17

Neden sadece bir GUID kullanmıyorsun? Çoğu diller bunu yapmak için yerleşik bir yol olmalıdır. O (çok makul sınır olmaksızın) benzersiz olması için garantisi yoktur.

Cevap 26/11/2008 saat 03:19
kaynak kullanıcı

oy
1

Ben, ancak bunun yerine dünyada, sadece olabilir güçlü karma işlevi seçme Oddthinking en fikir gibi:

  • MD5 sayılarının ilk 10 milyon (dizeleri olarak ifade edilen, + biraz tuz) üret
  • Çoğaltmaları denetlemek çevrimdışı yani üretimde gitmeden önce, (herhangi olmayacak sanırım)
  • yere bir dizi çiftleri Mağaza
  • Başvurunuz başladığında, dizi yük
  • Bir kimliği eklemek istediğinizde, bir sonraki numara seçebilir onun MD5 hesaplamak, bu dizide olup olmadığını kontrol edin ve veritabanında kimliği olarak kullanmak değilse. Aksi takdirde, bir sonraki numara seçmek

MD5 en hızlı ve bir dize bir diziye ait olmadığını kontrol size SEÇ önleyecektir.

Cevap 26/11/2008 saat 03:41
kaynak kullanıcı

oy
3

MySQL SEÇ CAST deyimi deneyin (RAND () * INT AS 1000000)

Cevap 26/11/2008 saat 08:51
kaynak kullanıcı

oy
1

Aslında daha önce yazdım bu konuda bir makale . Yine de koruyarak, 2, bir güç olmayan bir aralık üzerinde permütasyon oluşturmak için nasıl sonra, Robert Gould'un yanıt aynı yaklaşım, ancak ek olarak XOR katlama kullanılarak uygun bir uzunluğa, bir blok şifreleme kısaltmak için gösterilmiştir ve benzersizliği özelliği.

Cevap 26/11/2008 saat 11:13
kaynak kullanıcı

oy
0

Muhtemelen açınızı, ama ne auto_increments hakkında anlayamadım?

Cevap 27/11/2008 saat 19:11
kaynak kullanıcı

oy
1

Eğer gerçekten "rasgele" sayılar formu 0 999 999 9 almak istiyorsanız, o zaman çözüm zamanlar "randomizasyon" yapın ve sonra diske sonucu saklamaktır.

"Rastgele bir sayı olsun" yerine, O istediğiniz sonucu elde etmek zor değil, ama daha "sayılarla uzun bir liste yapmak" gibi düşün.

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

Ayrıca $ numaraları (bir veritabanında depolamak) içinde geçerli konuma bir işaretçi gerek; 0 ile başlar ve bunu yeni bir numarası lazım her zaman artırır. (Eğer işaretçileri kullanmak için sevmiyorum,) Yoksa array_shift (kullanabilirsiniz) veya (array_pop.)

Cevap 27/11/2008 saat 23:41
kaynak kullanıcı

oy
1

Düzgün PRNG (Sözde Rastgele Sayı Üreticisi) algoritması aynı durumda asla bu süre boyunca bir döngü zamanı olacaktır. Eğer buradan alınan sayısında PRNG eyaletinin tamamını maruz varsa, jeneratörün dönemi için benzersiz garanti bir numara alacak.

Bunu yapar Basit PRNG 'denir doğrusal eşlik bir formül dolaşır' PRNG:

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

faktörlerin sağ çifti kullanarak bir 32 bitlik akümülatör ile basit PRNG 2 ^ 30 (yaklaşık 1 milyar dolar) bir süre alabilir. Eğer hesaplama aracı 'AX' kısmını tutmak için uzun uzun geçici bir değişken 64 bit gerektiğini unutmayın. Çoğu hepsi değilse C derleyicileri bu veri türünü destekleyecek. Ayrıca çoğu SQL ağızları üzerine bir sayısal veri türü ile yapmak mümkün olmalıdır.

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

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

Bir İ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 kriptografik güvenli değildir (tanım gereği) olduğuna dikkat edin. Ondan üretilen son numarayı biliyorsanız bir sonraki ne yapacağını tahmin edebilirsiniz. Ne yazık ki aynı anda kriptografik güvenlik ve garantili olmayan tekrarlanabilirlik alamayan inanıyoruz. Bir PRNG kriptografik olarak güvenli olması için (örneğin Blum Blum Shub ) bu numaralar dizi tahmin izin vermek için oluşturulmuş bir yeterli sayıda durum maruz olabilir. Bu nedenle dahili durum süresi oluşturulabilir olası değerler sayısından daha uzun olacaktır (iyi güvenlik amacıyla) üretilir sayıda daha geniş ve bir. Bu maruz numara süre içinde benzersiz anlamına gelir.

Benzer nedenlerden dolayı, aynı gibi uzun dönem jeneratörler geçerlidir Mersenne Twister.

Cevap 27/11/2008 saat 23:59
kaynak kullanıcı

oy
1

9999999 arasındaki numaralara 0000000 içeren bir dizi oluşturmak ve sonra bu dizide bu sayıların rastgele seçim almak ve Max o sırada max azaltmak en yüksek değere sahip aldı numaralar değerlerini takas olur bu bir yol hakkında gitmek için birkaç yol vardır 1 ve yeni maksimum bu dizinin başka bir rasgele elemanını almak

tek Max azaltılması her zaman

Örneğin (temel olarak) için: (sağ fiili programda çıkarılmalıdır yorumlar getirirler) Rndfunc kullandığınız ne olursa olsun rasgele sayı üreteci işlevine bir çağrıdır

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

o zaman almak istediğiniz her numara için bunu yapmaya devam, ancak çok büyük diziler kullanma seçeneği olması gerekir

aşağıdaki gibi başka bir yöntem olabilir: bir sayı üretmek ve bu yeni numarayı almaya ve bu durumda dizideki son element ilk gelen yarım olan değer ile mukayese sonra dinamik sonra büyüyebilir bir dizi içine saklamak o aşağı yukarı gidip veya bunu karşılaştırıldığında sayısından büyük veya daha küçük hava şartlarına bağlı olarak daha sonra bir eşleşme değilse ilk sayı, başka bir rasgele sayı almak büyüklüğüne göre diziyi sıralamak eşleşirse aldı ve olurdu mesafenin yarısı liste yarısı, bu maç ve karşılaştırarak olduğunuzdan daha fazla veya daha az olduğu vermez her zaman.

Her zaman o zaman bir kez kontrol edip orada dengi değil ve sonra sayı listesine eklenir ve liste artan sırada kabineye olarak durdurmak birinin bir boşluk boyutuna ulaşana kadar böyle devam sen olana kadar böyle devam eder, bunu yarıya indirmek rasgele sayılar toplama yapılır ... Bu yardımcı olur umarım ..

Cevap 27/01/2012 saat 14:05
kaynak kullanıcı

oy
0

Eğer rastgele sayılar tekrarlayan olmadığını sağlamak istiyorsanız (açıklandığı gibi, bir tekrarlanmayan rastgele sayı-üreteci gerekir burada ).

Temel fikir, aşağıdaki formüle ki seed * seed & pherhangi bir giriş için tekrarlanmayan rastgele sayılar meydana getirecek x such that 2x < pve p - x * x % polmayan tekrarlayan, ama sadece aswell diğer rasgele sayı üretir p = 3 mod 4. Yani temelde tüm ihtiyacınız kadar yakın tek bir primnumber olduğu 9999999kadar mümkün. Ama çok büyük kimlikleri oluşturulur veya çok az kimlikleri oluşturulur ya olumsuz ile çaba tek bir okuma alanına azaltılabilir Bu şekilde.

Bu algoritma, çok iyi permute değildir, bu yüzden XOR veya ek veya tohumlar ve üretilen değer arasında 1-to-1-bir ilişki bozmadan tam değerini değiştirmek için başka bir yaklaşım iki ile birleştirilmesi tavsiye.

Cevap 04/10/2015 saat 22:49
kaynak kullanıcı

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