shuffle
Bademeister
- php
Hi.
Ich hab ein Array, das ich mittels der Funktion shuffle zufällig mische (jedenfalls versuche ich das):
$arr = array(1,3,5,7,9);
shuffle($arr);
Nun hab ich das geschätzte 60mal nacheinander gemacht, und genau drei(!) verschiedene Ergebnisse herausbekommen: eines anfangs ein- oder zweimal, danach ca. 40mal folgendes:
Array ( [0] => 5 [1] => 3 [2] => 1 [3] => 7 [4] => 9 )
und danach durchweg das:
Array ( [0] => 1 [1] => 9 [2] => 7 [3] => 5 [4] => 3 )
Ich nutze PHP 5.3, laut Handbuch muss shuffle seit PHP 4.2 nicht mehr initialisiert werden. Wenn dies schlicht falsch wäre, wäre es ja kein Problem, shuffle einfach zu initialisieren. Ist es im Grunde so auch nicht, aber mich irritiert enorm, dass das Ergebnis immer für ne Weile, aber nicht global konstant ist. Was nimmt denn PHP als Input fürs Initialisieren? Die aktuellen Minuten? :-) Kann ja nicht deren Ernst sein.
Hat jemand Ideen, was da los ist?
Danke, viele Grüße
der Bademeister
Hello,
Ich hab ein Array, das ich mittels der Funktion shuffle zufällig mische (jedenfalls versuche ich das):
$arr = array(1,3,5,7,9);
shuffle($arr);
>
> Nun hab ich das geschätzte 60mal nacheinander gemacht, und genau drei(!) verschiedene Ergebnisse herausbekommen: eines anfangs ein- oder zweimal, danach ca. 40mal folgendes:
>
> Array ( [0] => 5 [1] => 3 [2] => 1 [3] => 7 [4] => 9 )
>
> und danach durchweg das:
>
> Array ( [0] => 1 [1] => 9 [2] => 7 [3] => 5 [4] => 3 )
Auf was für einem System? 32Bit oder 64Bit?
Das hatten wir doch schon mal in einem Thread mit mir und globe.
Ich glaube, es war dieser hier:
<http://forum.de.selfhtml.org/archiv/2009/6/t187722/#m1248486>
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
![](http://selfhtml.bitworks.de/Virencheck.gif)
--
☻\_
/▌
/ \ Nur selber lernen macht schlau
<http://bergpost.annerschbarrich.de>
Hi nochmal.
Ok, shuffle basiert nur auf einer naiven Nutzung der Funktion rand, wie aus den Kommentaren zu shuffle hervorgeht. Wenig überraschend ist dann, dass rand das gleiche Problem hat. Es liefert für eine Weile (wenige Minuten) einen konstanten Wert, der dann wechselt. Und laut Handbuch muss rand ebenso seit PHP 4.2 nicht mehr initialisiert werden.
Daher ist shuffle gewissermaßen aus dem Schneider, meine obige Frage gilt denn der Funktion rand.
Viele Grüße,
der Bademeister
Hello,
Ok, shuffle basiert nur auf einer naiven Nutzung der Funktion rand, wie aus den Kommentaren zu shuffle hervorgeht. Wenig überraschend ist dann, dass rand das gleiche Problem hat. Es liefert für eine Weile (wenige Minuten) einen konstanten Wert, der dann wechselt. Und laut Handbuch muss rand ebenso seit PHP 4.2 nicht mehr initialisiert werden.
Daher ist shuffle gewissermaßen aus dem Schneider, meine obige Frage gilt denn der Funktion rand.
Hast Du es denn schon mit rand() versucht?
Dazu kannst Du dir die Keys auch vorher rausziehen mit array_keys().
Ist ein bisschen umständlich, aber dafür vielleicht wirkungsvoller?
Könnte es sein, dass die bei Shuffle vergessen haben, den Sand zu streuen?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Tach.
Ok, shuffle basiert nur auf einer naiven Nutzung der Funktion rand, wie aus den Kommentaren zu shuffle hervorgeht.
Was auch immer Du in diesem Fall unter "naiv" verstehst ... Die zuständige Funktion array_data_shuffle in ext/standard/array.c implementiert das, was Wikipedia als die Durstenfeld-Version des Fisher-Yates shuffles bezeichnet. Und ja, sie greift dabei ebenso wie rand in PHP auf die Funktion php_rand der PHP-API zurück.
Wenig überraschend ist dann, dass rand das gleiche Problem hat. Es liefert für eine Weile (wenige Minuten) einen konstanten Wert, der dann wechselt. Und laut Handbuch muss rand ebenso seit PHP 4.2 nicht mehr initialisiert werden.
Auch hier die Frage: Wie sieht der Code aus, mit dem Du das getestet hast?
Tach.
Nun hab ich das geschätzte 60mal nacheinander gemacht, und genau drei(!) verschiedene Ergebnisse herausbekommen: eines anfangs ein- oder zweimal, danach ca. 40mal folgendes:
Das kann ich mit folgendem Testcode nicht nachvollziehen:
for ($i = 0; $i < 30; $i++) {
$arr = array(1,3,5,7,9);
printArr($arr);
echo " -> ";
shuffle($arr);
printArr($arr);
echo "\n";
}
function printArr($a) {
for ($i = 0; $i < sizeof($a); $i++) {
echo $a[$i];
}
}
Den habe ich zwar unter PHP 5.2 laufen lassen, aber an shuffle und dem restlichen Kram für Zufallszahlen konnte ich in den C-Sources keine Änderungen feststellen. Sollte also die gleichen Ergebnisse liefern wie unter PHP 5.3.
Ich nutze PHP 5.3, laut Handbuch muss shuffle seit PHP 4.2 nicht mehr initialisiert werden.
Richtig. Die entsprechende Funktion überprüft selber, ob der Generator bereits einmal initialisiert wurde und tut diese ggf. selber, bevor ein Ergebnis berechnet wird.
Was nimmt denn PHP als Input fürs Initialisieren? Die aktuellen Minuten? :-) Kann ja nicht deren Ernst sein.
Nein. Aus ext/standard/php_rand.h:
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (time(0) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
Die Funktion php_combined_lcg
findest Du in ext/standard/lcg.c, falls Dich die Details der Initialisierung interessieren.
Hat jemand Ideen, was da los ist?
Zeig erstmal Deinen Testcode. ;)
Hello,
Nein. Aus ext/standard/php_rand.h:
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (time(0) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
>
> Die Funktion `php_combined_lcg`{:.language-c} findest Du in ext/standard/lcg.c, falls Dich die Details der Initialisierung interessieren.
Der Fehler ist aber bekannt. Manche Systeme haben ihn, manche nicht.
Vielleicht hägt es nicht nur vom OS ab, sondern auch vom verwendeten C-Compiler? Dann wäre der Fehler gar nicht im PHP-Source-Code zu suchen, sondern im Compiler?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
![](http://selfhtml.bitworks.de/Virencheck.gif)
--
☻\_
/▌
/ \ Nur selber lernen macht schlau
<http://bergpost.annerschbarrich.de>
Tach.
Der Fehler ist aber bekannt. Manche Systeme haben ihn, manche nicht.
Irgendwelche Quellen zu dieser Aussage? Die würden sicher auch dem OP helfen.
Ich habe inzwischen das Skript aus meinem vorigen Beitrag auf folgenden Systemen getestet:
Debian 5.0.5, 64-bit, PHP 5.2.6
Ubuntu 9.10, 32-bit, PHP 5.2.10
openSUSE 10.2, 32-bit, PHP 5.2.6
Windows XP, 32-bit, PHP 5.2.0
Jeweils sowohl CLI als auch als Apache-Modul. Auf keinem davon ließ sich das beschriebene Problem nachvollziehen.
Hello,
Der Fehler ist aber bekannt. Manche Systeme haben ihn, manche nicht.
Irgendwelche Quellen zu dieser Aussage? Die würden sicher auch dem OP helfen.
Ich habe inzwischen das Skript aus meinem vorigen Beitrag auf folgenden Systemen getestet:
Debian 5.0.5, 64-bit, PHP 5.2.6
Ubuntu 9.10, 32-bit, PHP 5.2.10
openSUSE 10.2, 32-bit, PHP 5.2.6
Windows XP, 32-bit, PHP 5.2.0Jeweils sowohl CLI als auch als Apache-Modul. Auf keinem davon ließ sich das beschriebene Problem nachvollziehen.
Das ist ja das Problem, dass wir (Tom, Globe) damals auch nicht herausgefunden haben, woran es lag. Es gabe aber mehrere Postings in unterschiedlichen Foren dazu im Netz.
Darum dachten wir auch: Vielleicht mangelnder Arbeitsspeicher?
Jedenfalls besteht noch die Vermutung, dass es (auch) am Compiler liegt.
Wenn ich mir Deinen Testcode ansehe, dünkt mir aber was anderes. Das muss ich aber selber erstmal ausprobieren. Ich werde es mal auf die schnelle Liste setzen :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Tach.
Dafür, daß hier letzte Woche kurzerhand ein ernsthaftes Problem in PHPs rand-Funktion diagnostiziert wurde, kommt jetzt aber erstaunlich wenig Feedback.
Ist das Problem gelöst? Mich würde ja interessieren, wie es sich rekonstruieren läßt, um der Sache ggf. auf den Grund gehen zu können. Wäre doch ganz interessant.