AMD Phenom II X6 1090T | 2x 4GB Kingston | Geforce GTX 560TI | Creative I-Trigue L3450
"Chaos kan niet uit de hand lopen"
"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney
mt_rand() heeft dat probleem in mindere mate of niet (die discussie ga ik hier niet aan
rand() vs mt_rand():
http://portfolio.technoized.com/notes/26
Dit noemt men dus overigens anecdotal evidence, dus wellicht praat ik nu poep, maar het is het proberen waard lijkt me.
Edit: heb zelf even wat tests gedaan en het hangt natuurlijk helemaal af van de range van getallen die je door de functie laat genereren (een kleiner bereik met een hoger aantal iteraties levert natuurlijk veel meer dubbele resultaten op), maar als ik de volgende code gebruik, krijg ik weinig verschillen te zien wanneer ik de verschillende combinaties probeer (hoog aantal iteraties/grote range, hoog aantal iteraties/kleine range, klein aantal iteraties/kleine range, klein aantal iteraties/grote range.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| $iterations = 10000; $knownA = array(); $countDoublesA = 0; for ($i = 0; $i < $iterations; $i++) { $tmpNumA = rand(1, 10000000); if (!in_array($tmpNumA, $knownA)) { $knownA[] = $tmpNumA; } else { $countDoublesA++; } } $knownB = array(); $countDoublesB = 0; for ($x = 0; $x < $iterations; $x++) { $tmpNumB = mt_rand(1, 10000000); if (!in_array($tmpNumB, $knownB)) { $knownB[] = $tmpNumB; } else { $countDoublesB++; } } echo "<b>rand()</b>"; echo "Aantal unieke waarden gegenereerd over ".$iterations." iteraties met rand(): ".count($knownA)."<br>"; echo "Aantal dubbele waarden gegenereerd over ".$iterations." iteraties met rand(): ".$countDoublesA."</p>"; echo "<p><b>mt_rand()</b>"; echo "Aantal unieke waarden gegenereerd over ".$iterations." iteraties met mt_rand(): ".count($knownB)."<br>"; echo "Aantal dubbele waarden gegenereerd over ".$iterations." iteraties met mt_rand(): ".$countDoublesB."</p>"; |
[ Voor 66% gewijzigd door Crayne op 10-11-2009 19:54 ]
Je vergelijking is de huidige code niet erg eerlijk omdat je in de bovenste loop tot 1000000 doet en in de onderste tot 1000.
Bij beide methoden zit ik op ongeveer 64% unieke getallen als je dezelfde range gebruikt.
Door iets vies te doen, kreeg ik bijna allemaal unieke >99%:
1
2
3
| <?php $tmpNumA = round( rand(1, $iterations) * rand() ); ?> |
"Chaos kan niet uit de hand lopen"
Crayne wat ik uit jou code begrijp is dat je een simpel getal wil hebben en kijkt of deze al eerder is voorgekomen. Dat is opzich wel mogelijk want je zou elke keer dezelfde procentuele kans moeten hebben. (oftewel, altijd hetzelfde getal 4 moet in theorie mogelijk zijn).
Wat mijn probleem alleen was dat hij een bepaald patroon volgde. Dus bijvoorbeeld eerst 3 dan 5 dan 6, dan weer 3 dan 5 dan 6 om het makkelijk te zeggen.
De code zag er alsvolgt uit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| for($i=0; $i<1000; $i++) { $title_en = ''; $title_fr = ''; $title_de = ''; $title_es = ''; $title_nl = ''; // Generate random titles in multilanguage $forlus = rand(8, 20); for($j=0; $j<$forlus; $j++) { $title_en .= $lorem_en[rand(0,count($lorem_en))]." "; $title_fr .= $lorem_fr[rand(0,count($lorem_fr))]." "; $title_de .= $lorem_de[rand(0,count($lorem_de))]." "; $title_es .= $lorem_es[rand(0,count($lorem_es))]." "; $title_nl .= $lorem_nl[rand(0,count($lorem_nl))]." "; } $geonameId = rand(2050000, 3050405); $randommaand = rand(1,12); $month = sprintf("%02d", $randommaand ); $randomdag = rand(1,28); $day = sprintf("%02d", $randomdag ); $year = rand(1200,2009); $historycat = rand(0,6); $getal++; $importid = sprintf("%05d", $getal ); $importid = "historytestdata".$importid.";"; echo "'".$title_en."', '".$title_fr."', '".$title_de."', '".$title_es."', '".$title_nl."', '".$geonameId."', '".$day."', '".$month."', '".$year."', '".$historycat."', '".$importid."'<br />"; } |
Op deze manier kreeg ik na een tijdje precies hetzelfde patroon als in het begin. Bij 1000x had elke rij ongeveer wel een dubbelganger.
Ik heb nu alle functie's vervangen door mt_rand, en dit geeft geen dubbelgangers. Maar ik blijf het raar vinden waarom php dit dan toch als standaard functie houdt.
AMD Phenom II X6 1090T | 2x 4GB Kingston | Geforce GTX 560TI | Creative I-Trigue L3450
Dat is niet zo raar, omdat geen enkele random number generator echt random is. Er zit altijd een vorm van structuur in, waarbij zaken als seeds etc gebruikt worden om zo random mogelijk te laten lijken.wel raar eigenlijk dat zo'n standaard rand functie toch een patroon opleverd
De kunst bij random nummer generatie is om het herhalingspatroon zoveel mogelijk te voorkomen en het bereik van potentiele 'random resultaten' zo breed mogelijk te maken en ook gelijkmatig te verspreiden.
Een goed (klassiek) boek wat dit zeer diepgaand behandeld is The Art Of Programming Volume 2 door Knuth. Hoewel sommige punten in dit boek niet even actueel zijn, staat het verhaal algemeen genomen nog steeds als een huis.
[ Voor 19% gewijzigd door Laurens-R op 10-11-2009 15:24 ]
En gezien de comments bij de rand() functie (http://php.net/manual/en/function.rand.php) gebeurt dat niet goed als je een min en max opgeeft.De kunst bij random nummer generatie is om het herhalingspatroon zoveel mogelijk te voorkomen en het bereik van potentiele 'random resultaten' zo breed mogelijk te maken en ook gelijkmatig te verspreiden.
[ Voor 6% gewijzigd door Creepy op 10-11-2009 15:41 ]
"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney
Dat zou ook verklaren waarom mijn lelijke hack eigenlijk bijna geen dubbele teruggeeft.Creepy schreef op dinsdag 10 november 2009 @ 15:40:
[...]
En gezien de comments bij de rand() functie (http://php.net/manual/en/function.rand.php) gebeurt dat niet goed als je een min en max opgeeft.
"Chaos kan niet uit de hand lopen"
Denk je?storeman schreef op dinsdag 10 november 2009 @ 14:12:
@crayne:
Je vergelijking is de huidige code niet erg eerlijk omdat je in de bovenste loop tot 1000000 doet en in de onderste tot 1000.
Ik heb ze gelukkig wel met dezelfde parameters getest, de code hier bevat blijkbaar een fout inderdaad, zal het even bijstellen.