Bademeister: shuffle

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

  1. 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>
    
    1. Hi Tom.

      Danke für den Link. Da wird die Frage (sinngemäß) aufgeworfen, aber nicht wirklich beantwortet, oder bin ich zu doof es zu finden?

      Auf was für einem System? 32Bit oder 64Bit?

      OpenSUSE 11.1., 32Bit.

      Viele Grüße,
      der Bademeister

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

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

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
    2. 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?

      --
      Always remember that you are unique. Just like everybody else.
  3. 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. ;)

    --
    Always remember that you are unique. Just like everybody else.
    1. 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>
      
      1. 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.

        --
        Always remember that you are unique. Just like everybody else.
        1. 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.0

          Jeweils 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

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  4. 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.

    --
    Always remember that you are unique. Just like everybody else.