2015-07-24 16 views
9

Ich bin gerade auf einen interesting question von ComputerGuru auf Hacker News gestoßen und kein Kommentar scheint eine überzeugende Antwort zu geben.Warum gibt mt_rand (1, PHP_INT_MAX) immer eine ungerade Zahl zurück?

Warum gibt mt_rand(1, PHP_INT_MAX) immer eine ungerade Zahl zurück?

Ich bin nicht der Autor der ursprünglichen Frage.

http://3v4l.org/dMbat

for ($i=0;$i<10000;$i++) 
{ 
    echo mt_rand(1, PHP_INT_MAX)."\n"; 
} 

Ausgang:

8571620074060775425 
7401021871338029057 
4351677773593444353 
1801559362708176897 
7848614552286527489 
... 
+5

Wahrscheinlich im Zusammenhang mit dieser, aus [PHP-Manual Seite für mt_rand] (http: // PHP. net/manual/de/function.mt-rand.php): * Vorsicht: Die Verteilung der Rückgabewerte von mt_rand() ist auf gerade Zahlen in 64-Bit-Builds von PHP ausgerichtet, wenn max größer als 2^32 ist.Wenn max größer ist als der von mt_getrandmax() zurückgegebene Wert, muss die Ausgabe des Zufallszahlengenerators hochskaliert werden. * – Simba

+4

Weil PHP_INT_MAX> mt_getrandmax(), [mehr Details] (https: //www.reddit. com/r/lolphp/Kommentare/3eaw98/mt_rand1_php_int_max_only_generates_odd_numbers/ctdhxha). – Sony

+2

http://assets.amuniversal.com/321a39e06d6401301d80001dd8b71c47 – j08691

Antwort

5

PHP_INT_MAX hier ist 2 -1 (64-bit signed int max).

mt_rand() verarbeitet jedoch keine so großen Werte. Der Mersenne-Twister generiert intern 32-Bit-Wörter, und PHP mt_getrandmax() ist nur 2 -1 (es wirft das höchste Bit weg).

Um einen Wert in Ihrem Wunsch min-max Bereich, mt_rand zuerst bekommen die 0 bis 2 -1 Zufallszahl zu erzeugen, skaliert es dann mit dieser Formel:

x = ((x/(mt_getrandmax() + 1)) * (max - min + 1)) + min; 

(Siehe Quelle rand.c und php_rand.h.)

Grundsätzlich skaliert es blind die intern generierte Nummer, um den übergroßen Bereich zu passen, ohne sogar eine Warnung zu erhöhen. Die Multiplikation mit dem übergroßen Bereich erzeugt eine Menge von Nullen in den niedrigen Bits, und das Hinzufügen von min (was 1 ist) macht das Ergebnis ungerade.

Das Problem ist noch dramatischer in hexadezimal, wo Sie, dass die unteren 32 Bits jeder Zahl sind vollständig nicht zufällig sehen:

for ($i = 0; $i < 10000; $i++) { 
    printf("%016x\n", mt_rand(1, PHP_INT_MAX)); 
} 

Ausgang:

41e0449b00000001 
53d33d7c00000001 
6ec8855700000001 
234140e000000001 
13a4581900000001 
77547beb00000001 
35a0660a00000001 
0d0cd44200000001 
... 

Es gibt eine Notiz in the manual, die versucht, davor zu warnen, obwohl es das Problem untertreibt:

Die Verteilung der Rückgabewerte mt_rand() ist auf gerade Zahlen bei 64-Bit-Builds von PHP ausgerichtet, wenn max über 2 hinausgeht. Dies liegt daran, dass, wenn max größer als der von mt_getrandmax() zurückgegebene Wert ist, der Ausgang des Zufallszahlengenerators hochskaliert werden muss.

(Sie sagt, sie zu geraden Zahlen vorbelastet sind, aber das ist nur wahr, wenn min selbst ist.)

+1

Große Erklärung, danke. Seltsam, dass PHP keinen Fehler/Ausnahme auslöst, wenn Sie ihm einen Wert übergeben und nicht "mt_getrandmax()". – ceejayoz

Verwandte Themen