Optimierung einer If-Abfrage



  • Hallo zusammen, ich hätte eine kleine Frage bzgl. einer If-Abfrage...

    if(!(x & 0x10204000000i64 &&
    			x & 0x700000i64 &&
    			x & 0x4210i64 &&
    			x & 0x204001000i64 &&
    			x & 0x2082000000i64 &&
    			x & 0x1004200i64 &&
    			x & 0x82002000i64 &&
    			x & 0x2002080i64 &&
    			x & 0x2082i64)) return true;
    

    Wie man unschwer erkennen kann, werden in der If-Abfrage lauter 64-Bit Konstanten verwendet. Jetzt zu meiner Frage: Wäre der Code möglicherhweise schneller, wenn die Konstanten in Arrays abgelegt werden? Bevor jetzt Sprüche kommen wie "Prober das doch selbst aus" muss ich dazu sagen, dass fast 1000 Zeilen die obige Form haben... Ich würde mir in etwa folgendes vorstellen:

    if(!(x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++])) return true;
    

    Für Anregungen bin ich dankbar....



  • Theoretisch wäre es langsamer (solange der Compiler das nicht wegoptimiert, wovon ich aber ausgehen würde); praktisch ist es auf modernen Computern eh nicht spürbar.

    Lass es einfach so.

    Gruß



  • PeterPan11 schrieb:

    if(!(x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++] &&
    			x & a[i++])) return true;
    

    Also ich bin jetzt nicht sicher ob das erlaubt ist. Schätze eher nicht. Bzw. ich bin sogar fast sicher dass es nicht erlaubt ist.
    (EDIT: doch, ist erlaubt)

    Die einzige Möglichkeit wie es erlaubt sein könnte, wäre, wenn && als Sequence-Point gilt (für && und || ist ja im Standard Short-Circuiting vorgeschrieben).
    (EDIT: und genau so ist es, && und || sind sequence points)

    Achja, wovon ich rede: man darf zwischen zwei Sequence-Points nicht mehrfach die selbe Variable ändern, wie du es mit i++ machen würdest. Also sowas wie printf("%d, %d\n", i++, i++) ist NICHT erlaubt.

    Aber egal. Es wäre, selbst wenn erlaubt, höchst schwindeliger Code, und daher solltest du es nicht so machen. OK wären natürlich wenn du "i++" durch Konstanten/Literale ersetzt:

    if(!(x & a[0] &&
    			x & a[1] &&
    			x & a[2] &&
    			x & a[3] &&
    			x & a[4] &&
    			x & a[5] &&
    			x & a[6] &&
    			x & a[7] &&
    			x & a[8])) return true;
    

    Oder gleich ne Schleife:

    for (size_t i = 0; i < 9; i++)
        if((x & a[i]) == 0)
            return false;
    return true;
    


  • sehe ich auch so, wie chrisber, aber:

    if(!(x & 0x10204000000i64 &&
                x & 0x700000i64 &&
                x & 0x4210i64 &&
                x & 0x204001000i64 &&
                x & 0x2082000000i64 &&
                x & 0x1004200i64 &&
                x & 0x82002000i64 &&
                x & 0x2002080i64 &&
                x & 0x2082i64)) return true;
    

    würd ich niemals in nem quellcode stehen haben wollen... das würde vrmtl so aussehen:

    bool is_strange(long long value)
    {
      const long long is_a = 0x10204000000i64;
      const long long have_a = 0x700000i64;
      /*...*/
    
      return !(value & is_a && value & have_a);
    }
    
    bool foo(long long value)
    {
      if(is_strange(value))
        return true;
    
    /*...*/
    }
    

    ansonsten kannst du dir bei so was auch immer gut den erzeugten asm-code angucken - selbst, wenn man nicht all zu viel davon versteht, wird man doch mit ein wenig googlen erkennen, was die cpu mit dem jeweiligen code nacheinander abarbeiten muss.

    bb



  • am besten wäre es, wenn du sowohl if als auch die logischen und's weglässt:

    return (
               (x & 0x10204000000i64) &
               (x & 0x700000i64) &
               (x & 0x4210i64) &
               (x & 0x204001000i64) &
               (x & 0x2082000000i64) &
               (x & 0x1004200i64) &
               (x & 0x82002000i64) &
               (x & 0x2002080i64) &
               (x & 0x2082i64)
            ) == 0i64;
    


  • Wobei bloss leider ganz was anderes rauskommt als beim ursprünglichen Code.



  • gelöscht, war falsch.



  • hustbaer schrieb:

    Also ich bin jetzt nicht sicher ob das erlaubt ist. Schätze eher nicht. Bzw. ich bin sogar fast sicher dass es nicht erlaubt ist.

    Doch, es ist erlaubt.

    §5.14/2: Logical AND operator schrieb:

    All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated.



  • Hihi, OK, steht sogar auf der Wikipedia Seite hier
    http://en.wikipedia.org/wiki/Sequence_point

    Gleich der erste Punkt.

    Krass 😃



  • Aber du hast Recht, schön ist sowas wie hier im Beispiel sicher nicht. 😉

    Ich würde auch eine Schleife nehmen.



  • Gelöscht, war falsch. Ich habe die && gedanklich übersehen, die ja wegen der Forward-Auswertung etwas ganz Anderes bewirken, als ich "gelesen" habe.



  • Nagut, ich denke, ich werd den Code so lassen wie er ist.
    Was etwas an Laufzeitvorteil bringen kann ist die Unterscheidung zwischen 32Bit und 64Bit Literalen (Nicht alle müssen zwangsläufig in 64Biz gestopft werden).
    Der Compiler scheint an dieser Stelle nicht selbststaändig zu optimieren.

    Trotzdem Danke für die vielen Tipps!!!


Anmelden zum Antworten