Reihenfolge der Addition



  • Hallo

    Ich habe zwei Funktionen geschrieben, die eigentlich exakt denselben Wert zurückgeben sollten:

    key_t board_c::generate_random_key_1(void) {
      key_t result;
    
      result = 0;
    
      result += key_t(rand() & 15);
      result += key_t(rand() & 15) << 4;
      result += key_t(rand() & 15) << 8;
      result += key_t(rand() & 15) << 12;
      result += key_t(rand() & 15) << 16;
      result += key_t(rand() & 15) << 20;
      result += key_t(rand() & 15) << 24;
      result += key_t(rand() & 15) << 28;
      result += key_t(rand() & 15) << 32;
      result += key_t(rand() & 15) << 36;
      result += key_t(rand() & 15) << 40;
      result += key_t(rand() & 15) << 44;
      result += key_t(rand() & 15) << 48;
      result += key_t(rand() & 15) << 52;
      result += key_t(rand() & 15) << 56;
      result += key_t(rand() & 15) << 60;
    
      return result;
    }
    
    key_t board_c::generate_random_key_2(void) {
      return
        (key_t(rand() & 15)) +
        (key_t(rand() & 15) << 4) +
        (key_t(rand() & 15) << 8) +
        (key_t(rand() & 15) << 12) +
        (key_t(rand() & 15) << 16) +
        (key_t(rand() & 15) << 20) +
        (key_t(rand() & 15) << 24) +
        (key_t(rand() & 15) << 28) +
        (key_t(rand() & 15) << 32) +
        (key_t(rand() & 15) << 36) +
        (key_t(rand() & 15) << 40) +
        (key_t(rand() & 15) << 44) +
        (key_t(rand() & 15) << 48) +
        (key_t(rand() & 15) << 52) + 
        (key_t(rand() & 15) << 56) +
        (key_t(rand() & 15) << 60);
    }
    

    Das tun sie aber nicht, die generierten Zufallszahlen sind nicht identisch. Natürlich habe ich den Zufallsgenerator zuvor initialisiert, damit rand() diesselben Zahlen produziert.

    Ich vermute, die Reihenfolge bei der Addition in der zweiten Funktion wird vom Compiler verändert. Kann das sein? Oder aus welchen Gründen produzieren die beiden Funktionen unterschiedliche Pseudo-Zufallszahlen?

    Danke!



  • Ja in der 2. Variante überlässt Du es dem Compiler in welcher Reihenfolge die einzelnen Ausdrücke ausgewertet werden. + ist im Gegensatz zu ; oder && und || kein Sequenzpunkt. Ein gutes Beispiel, was passiert wenn man eine Funktion mit Seiteneffekten in einem Ausdruck mehrfach aufruft.

    DJohn



  • In welcher Reihenfolge er addiert ist nicht beobachtbar. Und in welcher Reihenfolge die rand()-Aufrufe gemacht werden, ist vom Standard her nicht definiert. Üblich ist erst hinten dann vorne, also sozusagen genau verkehrt herum.



  • Der + Operator ist linksbindend. Also a+b+c ist dasselbe wie (a+b)+c. Allerdings wird bei Dir eine Funktion mit "Seiteneffekten" mehrfach in ein und demselben Ausdruck verwendet. Der C++ Standard definiert aber nicht, in welcher Reihenfolge Unterausdrücke berechnet werden.

    Kleines Beispiel:

    unsigned u =  (unsigned(rand()) & 15) +
                 ((unsigned(rand()) & 15) << 4);
    

    Hier ist der dazugehörige Baum:

    +
             &                 <<
           /   \          &         4
     unsigned  15       /   \
         |        unsigned  15
       rand()         |
                    rand()
    

    Der Compiler darf jetzt, wenn er will, das rechte rand() zuerst aufrufen.

    Gruß,
    SP



  • Danke 🙂



  • Und warum wird die Reihenfolge nicht vom Standard definiert? Sind dadurch irgendwelche Geschwindigkeitsoptimierungen möglich?



  • Danke _) schrieb:

    Und warum wird die Reihenfolge nicht vom Standard definiert? Sind dadurch irgendwelche Geschwindigkeitsoptimierungen möglich?

    genau das


Log in to reply