Algoritme voor het genereren van een willekeurig getal

stemmen
7

Ik ben op zoek naar een willekeurig getal te genereren en overhandigt het aan een tafel in een database voor een bepaalde user_id. De vangst is, hetzelfde nummer niet tweemaal worden gebruikt. Er is een miljoen manieren om dit te doen, maar ik hoop dat iemand zeer enthousiast over algoritmen heeft een slimme manier van het oplossen van het probleem in een elegante oplossing die aan de volgende criteria wordt voldaan:

1) De kleinste hoeveelheid vragen aan de database worden gemaakt. 2) De kleinste hoeveelheid kruipen door een gegevensstructuur in het geheugen wordt gemaakt.

In wezen het idee is om het volgende te doen

1) Maak een willekeurig getal 0-9.999.999
2) Controleer de database om te zien of het nummer bestaat
OR
2) Query de database voor alle nummers
3) als het geretourneerde resultaat wedstrijden wat uit de db kwam
4) Als het overeenkomt, herhaalt stap 1, zo niet, probleem is opgelost.

Bedankt.

De vraag is gesteld op 26/11/2008 om 02:44
bron van user
In andere talen...                            


17 antwoorden

stemmen
1

Ik denk dat je zult merken dat je echt niet wilt om dit te doen. Als de nummers in de database te verhogen, zou je te veel tijd doorbrengen in de "zorg ervoor dat dit nummer wordt niet genomen" loop.

Persoonlijk, ik heb geluk met hashes als een alternatief hadden, maar om te komen tot een betere oplossing, zou ik echt nodig om te weten waarom je het op deze manier te doen.

antwoordde op 26/11/2008 om 02:51
bron van user

stemmen
1

Mijn ervaring was gewoon met behulp van de RNG in PHP. Ik vond dat het gebruik van een bepaalde grootte van het aantal (ik gebruik een int, dus ik heb een maximum van 4G). Ik rende een aantal tests en vond dat gemiddeld 500.000 iteraties, kreeg ik 120 enkele duplicaten. Ik heb nog nooit een drievoud na het uitvoeren van de lus een paar keer. Mijn "oplossing" was dan plaatst u gewoon en controleer of het niet lukt, dan is het genereren van een nieuwe ID en weer gaan.

Mijn advies is om hetzelfde te doen en te zien wat uw botsing tarief is & c en zien of het acceptabel is voor uw zaak.

Dit is niet optimaal, dus als iemand suggesties Ik ben ook op zoek :)

EDIT: Ik was beperkt tot 5 cijferig ID ([a-zA-Z0-9] {5,5}), hoe langer de id (meer combinatie, de weinig botsingen). Een md5 van de e-mail zou bijna nooit in strijd zijn, bijvoorbeeld.

antwoordde op 26/11/2008 om 02:51
bron van user

stemmen
17

Nee je algoritme is niet schaalbaar. Wat ik heb gedaan is om nummers in serie uit te geven (1 per keer) en daarna gaan ze door een XOR operatie om de bits waardoor me een schijnbaar willekeurige getallen wirwar. Natuurlijk zijn ze niet echt willekeurig, maar ze zien er zo aan gebruikers ogen.


[Bewerken] Aanvullende informatie

logica Dit algoritme gaat als volgt u een bekende sequentie te gebruiken om unieke nummers te genereren en dan moet je deterministisch te manipuleren, zodat ze niet seriële meer kijken. De algemene oplossing is om een ​​of andere vorm van encryptie, wat in mijn geval was het een XOR flipflop te gebruiken, omdat het zo snel als het kan krijgen, en het voldoet aan de garantie dat nummers nooit zal botsen.

U kunt echter andere vormen van encryptie te gebruiken, als je wilt liever iets meer willekeurige zoek getallen, over snelheid (zeggen dat je niet hoeft te veel ids genereren per keer). Nu is het belangrijkste punt bij het kiezen van een encryptie-algoritme is "de garantie dat nummers nooit zal botsen". En een manier om te bewijzen als een encryptie-algoritme kan deze garantie te voldoen is om te controleren of zowel het oorspronkelijke aantal en het resultaat van de encryptie hebben hetzelfde aantal bits, en dat de het algoritme is omkeerbaar (bijection).

[Dank zij Adam Liss & CesarB voor exapanding op de oplossing]

antwoordde op 26/11/2008 om 02:51
bron van user

stemmen
1

Het probleem is dat als je het genereren van willekeurige getallen is is heel goed mogelijk om duplicaten infinatly te produceren.

echter:

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

Hoewel dit zal doen wat je wilt ook, het is een slecht idee als dit zal niet schaal voor lang, eventualy zal uw array te groot worden en het zal een zeer lange tijd in beslag nemen om het genereren van een willekeurig die nog niet in uw db .

antwoordde op 26/11/2008 om 02:55
bron van user

stemmen
2

Ervan uitgaande dat:

  • De willekeur is nodig voor uniciteit, niet voor de veiligheid
  • Uw user_id is 32 bit
  • Uw limiet van 9999999 was slechts een voorbeeld

Kon iets eenvoudig met het willekeurige getal een 64 bit integer, waarbij de bovenste 32 bits met de tijdstempel (bij rij insert) en de onderste 32 bits van de user_id doen. Dat zou uniek, zelfs voor meerdere rijen met dezelfde gebruiker zijn, mits u de gewenste resolutie te gebruiken op uw tijdstempel, afhankelijk van hoe vaak u nieuwe rijen toe te voegen voor dezelfde gebruiker. Combineer met een unieke beperking op de willekeurige kolom en de vangst van een dergelijke fout in uw logica en dan gewoon opnieuw proberen.

antwoordde op 26/11/2008 om 03:00
bron van user

stemmen
1

Het is gemakkelijk om een pseudo-random number generator met een lange periode van nonrepetition te ontwerpen; zoals deze , die wordt gebruikt voor hetzelfde ding dat je het wilt voor.

BTW, waarom niet gewoon geven achtereenvolgens de userid's?

antwoordde op 26/11/2008 om 03:02
bron van user

stemmen
0

PHP heeft al een functie voor dit, uniqid . Het genereert een standaard uuid dat is geweldig als je toegang tot de gegevens van elders. Laat het wiel niet opnieuw uit te vinden.

antwoordde op 26/11/2008 om 03:06
bron van user

stemmen
6

Wilt u een over-the-top oplossing?

Ik neem aan willekeur is niet bedoeld om encryptie-kwaliteit, maar net genoeg om te ontmoedigen raden van de levensduur van een gebruiker door user_id zijn.

Tijdens de ontwikkeling, het genereren van een lijst van alle 10 miljoen nummers in de vorm van een string.

Eventueel voeren wat eenvoudige verwerking, zoals het toevoegen van een constante string naar het midden. (Dit is voor het geval dat het resultaat is te voorspelbaar.)

Geef ze tot een instrument dat genereert Perfect Hash functies , zoals gperf .

De resulterende code kan worden gebruikt om id van de gebruiker op runtime snel coderen in een unieke hash-waarde die wordt gegarandeerd niet botsen met andere hash-waarden.

antwoordde op 26/11/2008 om 03:16
bron van user

stemmen
17

Waarom ga je niet gewoon een GUID gebruiken? De meeste talen zou een ingebouwde manier om dit te doen. Het is gegarandeerd uniek (met zeer redelijke grenzen) te zijn.

antwoordde op 26/11/2008 om 03:19
bron van user

stemmen
1

Ik hou Oddthinking idee, maar in plaats van het kiezen van de sterkste hash-functie in de wereld, je kon gewoon:

  • Genereer de MD5's van de eerste 10 miljoenen nummers (uitgedrukt als strings, + wat zout)
  • Controleren op duplicaten offline , dus voordat je in de productie (Ik denk dat er zal niet zijn)
  • Bewaar de duplicaten in een array ergens
  • Wanneer uw toepassing wordt gestart, laadt de reeks
  • Wanneer u een ID in te voegen, kiest u het volgende nummer, het berekenen van de MD5, controleren of het in de array, en als het niet gebruiken als de ID in de database. Anders kiest u volgende nummer

MD5's zijn snel, en het controleren of een string maakt deel uit van een reeks zal u voorkomen dat een SELECT.

antwoordde op 26/11/2008 om 03:41
bron van user

stemmen
3

Probeer de verklaring in mysql SELECT CAST (RAND () * 1000000 AS INT)

antwoordde op 26/11/2008 om 08:51
bron van user

stemmen
1

Ik heb eigenlijk eerder geschreven een artikel over dit . Het heeft dezelfde aanpak als antwoord Robert Gould, maar bovendien laat zien hoe een blokversleuteling op een geschikte lengte te verkorten behulp xor vouwen, en hoe de permutaties over een bereik dat geen macht van 2 te genereren, terwijl behoud van de uniciteit eigendom.

antwoordde op 26/11/2008 om 11:13
bron van user

stemmen
0

Ik heb waarschijnlijk niet je punt, maar hoe zit het auto_increments vangen?

antwoordde op 27/11/2008 om 19:11
bron van user

stemmen
1

Als je echt wilt "random" getallen vorm 0-9 999 999 krijgen, dan is de oplossing is om de "randomisatie" een keer te doen, en dan sla het resultaat op uw schijf.

Het is niet moeilijk om het gewenste resultaat te krijgen, maar ik denk aan het meer als "een lange lijst met nummers", dan "krijg je een willekeurig getal".

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

Je moet ook een verwijzing naar de huidige positie in $ nummers (op te slaan in een database); beginnen met 0 en verhogen het elke keer dat u een nieuw nummer nodig. (Of je zou kunnen gebruiken array_shift () of array_pop (), als je niet wilt pointers te gebruiken.)

antwoordde op 27/11/2008 om 23:41
bron van user

stemmen
1

Een goede PRNG (Pseudo-Random Number Generator) algoritme zal een cyclustijd, gedurende welke het nooit zal worden in dezelfde staat te hebben. Als u de hele staat van de PRNG bloot te leggen van het aantal opgehaald uit het, vindt u een aantal gegarandeerd uniek voor de periode van de generator te krijgen.

Een eenvoudige PRNG die dit doet wordt de ' Linear congruential ' PRNG met een formule herhaalt:

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

Met behulp van de juiste paar factoren die je kunt een periode van 2 ^ 30 (ongeveer 1 miljard euro) van een eenvoudig PRNG met een 32 bit accumulator krijgen. Merk op dat je een 64 bit tijdelijke variabele moet lang lang om de tussenliggende 'AX' deel van de berekening te houden. De meeste, zo niet alle C-compilers zullen dit soort gegevens ondersteunen. Je moet ook in staat zijn om het te doen met een numeriek gegevens op de meeste SQL dialecten.

Met de juiste waarden van A en M kunnen we een random number generator met goede statistische en geometrische eigenschappen te krijgen. Er is een beroemde paper over dit geschreven door Fishman en Moore.

Voor M = 2 ^ 31-1 krijgen we kunnen de waarden van A hieronder te gebruiken om een ​​PRNG krijgen met een mooie lange periode (2 ^ 30 IIRC).

Goede Waarden van A:

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

Merk op dat dit type generator (per definitie) geen cryptografisch beveiligd. Als u weet dat het laatste nummer gegenereerd op basis van het u kan voorspellen wat het volgende zal doen. Helaas heb ik denk dat je cryptografische beveiliging en gegarandeerde niet-herhaalbaarheid niet kunt krijgen op hetzelfde moment. Een PRNG cryptografisch beveiligd (bijv Blum Blum Shub ) kan onvoldoende staat bloot een gegenereerde getal zodat het volgende nummer in de reeks te voorspellen. Daarom is de interne toestand is breder dan het gegenereerde nummer en (om een goede beveiliging) de periode langer dan het aantal mogelijke waarden die kunnen worden gegenereerd. Dit betekent dat de blootgestelde aantal niet uniek binnen de termijn zal zijn.

Om soortgelijke redenen hetzelfde geldt voor lange tijd generatoren zoals de mersennetwister.

antwoordde op 27/11/2008 om 23:59
bron van user

stemmen
1

er zijn een paar manieren om te gaan over dit een manier zou zijn om een ​​array te construeren met de nummers 0000000 door middel van 9999999 en kies vervolgens een greep uit deze nummers in deze array en wisselen de geplukte nummers waarden met de hoogste waarde Max vervolgens verminderen max door 1 en kies een ander willekeurig lid van deze array tot aan de nieuwe maximum

elke keer dat het verminderen van Max door één

bijvoorbeeld (in basis): (aan de rechterkant zijn opmerkingen die in het eigenlijke programma moet worden verwijderd) Rndfunc is een oproep aan wat random number generator functie die u gebruikt

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

dan is dit blijven doen voor elk nummer dat u wenst op te halen, maar je moet de mogelijkheid van het gebruik van zeer grote arrays

de andere methode zou zijn als volgt: genereer een getal en opslaan in een array die kunnen groeien dynamisch ook daarna kies een nieuw nummer en vergelijken met de waarde die halverwege van het eerste naar het laatste element in de array in casu het zou het eerste nummer uitgekozen als het overeenkomt kies een ander willekeurig getal, de array te sorteren op grootte en als er niet een match dan afhankelijk van het weer is groter of kleiner dan het nummer dat u het in vergelijking met u omhoog of omlaag in de lijst met de helft van de helft van de afstand, elke keer dat het komt niet overeen en is meer of minder dan wat u te vergelijken met.

elke keer dat een halvering van het tot je een gat grootte van één te bereiken dan een keer te controleren u en stoppen als er geen overeenkomst is, en vervolgens het nummer wordt toegevoegd aan de lijst en de lijst wordt herschikt in oplopende volgorde, zo voort en zo verder tot je bent gedaan plukken willekeurige getallen ... hoop dat dit helpt ..

antwoordde op 27/01/2012 om 14:05
bron van user

stemmen
0

Als u ervoor wilt zorgen dat de random-getallen niet herhalen, een niet te herhalen random number generator moet je (zoals beschreven hier ).

Het basisidee is dat de volgende formule seed * seed & pniet-herhalende willekeurige getallen om invoer wordt geproduceerd x such that 2x < pen p - x * x % pproduceert alle andere willekeurige getallen aswell niet-herhalend, maar alleen als p = 3 mod 4. Dus eigenlijk alles wat je nodig hebt is een enkele primnumber zo dicht 9999999mogelijk. Op deze manier de inspanning kan worden teruggebracht tot een enkele lezenveld, maar met het nadeel dat ofwel te groot ID's worden gegenereerd of te weinig ID's wordt gegenereerd.

Dit algoritme werkt niet erg goed verwisselen, dus ik zou aanraden het te combineren met ofwel XOR of toevoeging of een andere benadering van de exacte waarde te wijzigen zonder dat de 1-op-1-relatie tussen de zaden en de gegenereerde waarde te vernietigen.

antwoordde op 04/10/2015 om 22:49
bron van user

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