Ik heb nog altijd het vermoeden dat rand() niet random is, iig, niet volledig random.
Na mijn vorige experiment (let vooral op de totalen onderaan) heb ik nu een nieuw experiment bedacht. Een plaatje.
Ik geef de opdracht (source) om met x = rand(0, 500) en y= rand(0, 500) een plaatje pixel voor pixel in te kleuren. Daarna tel ik de witte pixels. Nu valt het me op dat het aantal witte pixels altijd 36% is. Nooit meer, nooit minder, op een paar getallen achter de komma na.
Nog erger, op mijn eigen computer had ik laatst een plaatje met een volledig raster erin. Je zag gewoon de knooppunten. Helaas had ik het niet opgeslagen.
Altijd 36%, wat voor conclusie mag ik daaruit trekken? Dat het aantal keer dat x en y al eerder samen zijn voorgekomen dus 36% is. Maar waarom nooit 37% laat staan 45%?
Heb ook even een programmaatje om mijn grafische rekenmachine gemaakt. Ook met pixels enz. Ik maak een veld van 30x30 en laat die ook random vullen met pixels en te het aantal witten. Nu kom ik met mijn rekenmachine telkens tussen de 35-40. Dus daar is de rand functie beter?
ps. over een forlus van 30*30=900 doet mijn rekenmachine al 52 seconden :( en dan heb ik het over een TI84+
Deze tabel geeft aan dat 99% van de keren dat je dit script runt, de chi-kwadraat meer moet zijn dan 69.22986, 90% van de keren groter dan 81.44925, etc.
Een eenvoudige vuistregel is te kijken naar de waardes tussen 40% en 70%; de chi-kwadraat zou dus ruwweg tussen 91 en 102 moeten liggen.
Een voorzichtige conclusie die ik trek na het script een aantal malen te hebben uitgevoerd is dat mt_rand() inderdaad beter is dan rand(), maar dat ook mt_rand() niet echt waanzinnig goed is.
De source van het script kun je hier vinden, en het script zelf hier.
Als random random zou moeten zijn, dan betekend dat toch dat er uiteindelijk dezelfde waardes uit moeten komen als je maar genoeg keer 'kop of munt' uitvraagt?
Als het daadwerkelijk zo zou zijn dat elke waarde even vaak voorkomt, dan is dat niet random ;-)
Als ik het plaatje 1000x1000 maak, kom ik met rand() zelfs op 98% wit uit :s
mt_rand ook op 36%
Dit is lokaal Windows XP Home PHP 5.1.2 Apache 2.0.55
Ik zal het zo ook nog even online testen...
Edit
Online kom ik op dezelfde resultaten uit (Windows 2000 bak met PHP 4.4.1 als ik me niet vergis.) Wat me wel opvalt, als er maar 1 mt_rand is (x of y maakt niet uit), dat hij dan wel altijd 36% blijft. En niet er tussen gaat zitten oid. (Zal vast weer te verklaren zijn, maar het viel mij gewoon op :) )
Heb ik Elwin's conclusie van een eerdere test dus weerlegd. rand() is sneller, maar op windows vrij onwillekeurig. (een raster krijgen vind ik geen willekeur!) mt_rand() is langzamer, maar 'betrouwbaarder' :)
In een boek dat ik heb (Dynamische websites met PHP) meen ik te hebben gelezen dat mt_rand() juist sneller is, zal het nog wel even nakijken..
edit: Ik citeer:
...
De functie mt_rand() werkt gemiddeld ongeveer vier keer sneller dan rand() en gebruikt een speciale generator, de Mersenne Twister (MT), die beter geschikt zou zijn voor cryptografie.
Bron: Dynamische website's met PHP
Daaronder staat nog een hoofdstukje over srand() en mt_srand(). Daar staat ook een stukje over wat er hier allemaal wordt getest. Ik denk niet dat de schrijver dit leuk vind, maargoed:
srand() en mt_rand()
Een generator voor aselecte getallen maakt vaak niet echt een aselect getal, maar een pseudo-aselect getal door willekeurig een getal te trekken uit een vaste reeks van standaardgetallen. Daardoor is de statische kans dat een specifiek getal vaker voorkomt dan andere getallen groot, waardoor het gegenereerde getal niet echt willekeurig is en uiteindelijk dus veel minder veilig.
U kunt dit voorkomen door de generator te initialiseren met een seed of 'zaadje'. Vanaf PHP 4.2.0 gebeurt dat automatisch, maar in oudere versies moet u hiervoor de functie srand() of mt_srand() gebruiken:
void srand ( int seed)
void mt_srand ( int seed)
De functie srand() en mt_srand() husselen of dobbelen de reeks standaardgetallen als het ware door elkaar met de integer in de parameter seed. Om echter te voorkomen dat u toch weer steeds dezelfde reekst getallen krijgt, moet u voor seed elke keer een andere integer gebruiken. Een standaardtechniek daarvoor is uitgaan van de tijd in seconden, milliseconden of zelfd microseveonden volgens de systeemklok van de server, omdat de tijd voortdurend verandert. Hiervoor kunt u de functie microtime() gebruiken, die een timestamp of tijdstempel teruggeeft met de huidige tijd als het aantal milliseconden en seconden dat is verstreken sinds het begin van het UNIX-tijdperk (1 januarie 1970 om 0:00:00). Het resultaat van microtime() is een string met milliseconden en daarna seconden. Als u dit resultaat vermenigvuldigt met een groot getal, bijvoorbeeld 1000000 (één miljoen) en daarop de cast (int) toepast, krijgt u een lange integer die u kunt gebruiken voor de parameter seed van srand() en mt_srand(), bijvoorbeeld: