2017-03-27 3 views
0

Was ist die performante Wahl zwischen:verschachtelte wenn vs. und Zustand

if(myConditionA){ 
    if (myConditionB){ 
     if (myConditionC){ 
      //do something 
     } 
    } 
} 

und

if(myConditionA && myConditionB && myConditionC){ 
    //do something 
} 

Was ist die beste Wahl und warum? Kommt es auf die Sprache an?

BEARBEITEN: Es ist keine Frage über die Codequalität.

+0

Hängt, wenn Sie sonst Bedingungen haben –

+0

nur grundlegende wenn, sonst keine Aussagen für diesen Fall – d3cima

+1

Es hängt auch von der Sprache ab. Die meisten, aber nicht alle Sprachen haben eine Kurzbewertung. Wenn dies nicht der Fall ist, ist die erste Version effizienter, da Sie die Short-Cut-Bewertung tatsächlich implementieren. Beachten Sie, dass, wenn die Bedingungen Nebenwirkungen haben und keine kurze Bewertung vorhanden ist, ein Unterschied im Verhalten zwischen den beiden bestehen kann. – trincot

Antwort

4

Was passiert, wenn man es versucht, und warum sollten Sie es erwarten, mit keinen Unterschied überhaupt zu sein, was der Compiler erzeugt? Es gibt keinen Unterschied in Ihrem Algorithmus zwischen den beiden.

unsigned int one (unsigned int myConditionA, unsigned int myConditionB, unsigned int myConditionC) 
{ 
    if(myConditionA){ 
     if (myConditionB){ 
      if (myConditionC){ 
       //do something 
       return(1); 
      } 
     } 
    } 
    return(0); 
} 
unsigned int two (unsigned int myConditionA, unsigned int myConditionB, unsigned int myConditionC) 
{ 
    if(myConditionA && myConditionB && myConditionC){ 
     //do something 
     return(1); 
    } 
    return(0); 
} 

00000000 <one>: 
    0: e3510000 cmp r1, #0 
    4: 13520000 cmpne r2, #0 
    8: 13a02001 movne r2, #1 
    c: 03a02000 moveq r2, #0 
    10: e3500000 cmp r0, #0 
    14: 03a00000 moveq r0, #0 
    18: 12020001 andne r0, r2, #1 
    1c: e12fff1e bx lr 

00000020 <two>: 
    20: e3510000 cmp r1, #0 
    24: 13520000 cmpne r2, #0 
    28: 13a02001 movne r2, #1 
    2c: 03a02000 moveq r2, #0 
    30: e3500000 cmp r0, #0 
    34: 03a00000 moveq r0, #0 
    38: 12020001 andne r0, r2, #1 
    3c: e12fff1e bx lr 

hah, okay das war hässlich, aber nur, weil, wie ich schrieb den Test, hatte diese schon das eine oder andere, aber nicht beides dann würde der Compiler den gleichen Code eindeutig hervorgebracht hat. Ein gemessener Leistungstest könnte also einen Unterschied zeigen, wenn Sie das sehen könnten, aber es ist ein schlechter Test.

00000000 <two>: 
    0: 10800006 beqz $4,1c <two+0x1c> 
    4: 00801025 move $2,$4 
    8: 10a00003 beqz $5,18 <two+0x18> 
    c: 00000000 nop 
    10: 03e00008 jr $31 
    14: 0006102b sltu $2,$0,$6 
    18: 00001025 move $2,$0 
    1c: 03e00008 jr $31 
    20: 00000000 nop 

00000024 <one>: 
    24: 08000000 j 0 <two> 
    28: 00000000 nop 

ein weiterer Befehlssatz.

00000000 <_one>: 
    0: 1d80 0002  mov 2(sp), r0 
    4: 0308   beq 16 <_one+0x16> 
    6: 0bf6 0004  tst 4(sp) 
    a: 0306   beq 18 <_one+0x18> 
    c: 15c0 0001  mov $1, r0 
    10: 0bf6 0006  tst 6(sp) 
    14: 0301   beq 18 <_one+0x18> 
    16: 0087   rts pc 
    18: 0a00   clr r0 
    1a: 0087   rts pc 

0000001c <_two>: 
    1c: 1d80 0002  mov 2(sp), r0 
    20: 0308   beq 32 <_two+0x16> 
    22: 0bf6 0004  tst 4(sp) 
    26: 0306   beq 34 <_two+0x18> 
    28: 15c0 0001  mov $1, r0 
    2c: 0bf6 0006  tst 6(sp) 
    30: 0301   beq 34 <_two+0x18> 
    32: 0087   rts pc 
    34: 0a00   clr r0 
    36: 0087   rts pc 

verschiedene Compiler

00000000 <one>: 
    0: e3510000 cmp r1, #0 
    4: 13a01001 movne r1, #1 
    8: e3500000 cmp r0, #0 
    c: 13a00001 movne r0, #1 
    10: e3520000 cmp r2, #0 
    14: e0000001 and r0, r0, r1 
    18: 13a02001 movne r2, #1 
    1c: e0000002 and r0, r0, r2 
    20: e12fff1e bx lr 

00000024 <two>: 
    24: e3510000 cmp r1, #0 
    28: 13a01001 movne r1, #1 
    2c: e3500000 cmp r0, #0 
    30: 13a00001 movne r0, #1 
    34: e3520000 cmp r2, #0 
    38: e0000001 and r0, r0, r1 
    3c: 13a02001 movne r2, #1 
    40: e0000002 and r0, r0, r2 
    44: e12fff1e bx lr 

ein anderes Ziel mit dem anderen Compiler

00000000 <one>: 
    0: 27bdfff8 addiu $29,$29,-8 
    4: afbe0004 sw $30,4($29) 
    8: 03a0f025 move $30,$29 
    c: 0005082b sltu $1,$0,$5 
    10: 0004102b sltu $2,$0,$4 
    14: 00410824 and $1,$2,$1 
    18: 0006102b sltu $2,$0,$6 
    1c: 00221024 and $2,$1,$2 
    20: 03c0e825 move $29,$30 
    24: 8fbe0004 lw $30,4($29) 
    28: 03e00008 jr $31 
    2c: 27bd0008 addiu $29,$29,8 

00000030 <two>: 
    30: 27bdfff8 addiu $29,$29,-8 
    34: afbe0004 sw $30,4($29) 
    38: 03a0f025 move $30,$29 
    3c: 0005082b sltu $1,$0,$5 
    40: 0004102b sltu $2,$0,$4 
    44: 00410824 and $1,$2,$1 
    48: 0006102b sltu $2,$0,$6 
    4c: 00221024 and $2,$1,$2 
    50: 03c0e825 move $29,$30 
    54: 8fbe0004 lw $30,4($29) 
    58: 03e00008 jr $31 
    5c: 27bd0008 addiu $29,$29,8 

Auch unoptimized bekam ich das gleiche Ergebnis. Es gibt keinen Unterschied zwischen den beiden, warum sollte der Compiler eine Differenz erzeugen, die einen Leistungsunterschied darstellt?

+0

Sicher ist es möglich, auf einen Compiler zu stoßen, der aus irgendeinem Grund weiter den zweiten (und dritten) Vergleich zu bewerten, wenn der erste nicht wahr ist, oder oder vergleicht die drei in irgendeiner Weise, dass sie nicht bis nachher vergleichen, vergleichen , speichere z Flag, vergleiche das save z Flag, vergleiche das save z Flag, addiere/und die z Flags. Aber ich würde diesen Compiler vermeiden ... –

+0

Hätte aufgefrischt, aber die Antwort klang sehr herablassend – dwn

+0

Das Poster stellte eine Frage, ohne sich zu bemühen, obwohl es ohnehin keine Stackoverflow-Frage war. So, als schreibst du deine Hausaufgaben wortwörtlich. aber dieser ist viel einfacher als Hausaufgaben zu verstehen. –

2

Wenn Sie so etwas wie haben, dass der beste Weg zu gehen, die durch den Pfeil Code wie das zu vermeiden:

if (!myConditionA) 
    return; 
if (!myConditionB) 
    return; 
if (!myConditionC) 
    return; 
//do something 

Sie auch alle die Bedingung in eine andere Funktion werfen und verwenden Sie es mögen:

if (!aggergateCondition()) 
    return; 
// do something 

Es macht Ihren Code sauber und lesbar und reduziert die Anzahl der Vertiefungen, die Struktur abflachen.

EDIT:

Die leistungsfähigeren Weise ist theoretisch die Form mit den && Aussagen. Warum? Weil es nicht verzweigt und es faul ist. Die if-Anweisungen sind auch etwas faul, aber sie verzweigen sich.

Aber das muss nicht unbedingt halten. Sie müssen branch prediction in Rechnung, die möglicherweise einige dieser if-Anweisungen weglassen und könnte häufiger unter der &&-Operator brechen (unterlassen nur eine if Anweisung ist viel einfacher). Es könnte auch die Möglichkeit bestehen, dass einige Optimierungen vom Compiler ausgeführt werden, was dazu führen könnte, dass diese beiden Fälle zu demselben Assembly- oder Byte-Code führen würden.

Also im Grunde - es ist schwer zu sagen, welche eine bessere Leistung hat, wegen der Magie, die hinter den Kulissen von Compiler-Optimierungen und sogar CPU-Architektur passiert.

Wenn Sie einige vorzeitige Optimierung Tutorial möchte ich empfehlen this Buch zu Ihnen :)

+0

natürlich, würde ich meine Bedingungen aggregieren, aber es ist keine Frage über die Qualität des Codes :) es ist mehr eine Frage über den schnellsten Code. – d3cima

+0

Einige "schlechte" Literaturempfehlungen für Sie hinzugefügt. –

+0

Zu sagen, dass die Verwendung von '&&' nicht verzweigt ist falsch. Wenn Sie sich den generierten Code ansehen, werden Sie sehen, dass er tatsächlich verzweigt. In vielen (meisten?) Sprachen führt die Benutzung des '&&' -Operators zu einer Verzweigung, wenn die Sprache die Auswertung kurzschließt. Wenn Sie 'if (A && B && C)' haben und sich 'A' als falsch herausstellt, wird es einen Zweig um die Bewertung von' B' und 'C' geben. –

1

Es gibt wenig Unterschied zwischen dem Kurzschluss && und dem verschachtelten if s im kompilierten Code, aber es gibt noch Möglichkeiten, diese Situation zu optimieren. Es hängt von der Wahrscheinlichkeit jeder Bedingung ab. Dies kann durch profilgeführte Optimierung festgestellt werden oder Sie können versuchen, die Statistiken empirisch zu ermitteln.

Wenn jede boolesche Bedingung die gleiche ungefähre Wahrscheinlichkeit hat, dann spielt die Reihenfolge keine Rolle; Wenn jedoch eine oder mehrere eine größere Wahrscheinlichkeit haben, falsch zu sein, dann sollten sie von höchstwahrscheinlich falsch sein, um höchstwahrscheinlich wahr zu sein. Wenn alle von ihnen ziemlich wahrscheinlich wahr sind (Multiplizieren aller Wahrscheinlichkeiten von wahren Ausbeuten> = 0,5), dann wird das Verwenden des bitweisen & Operators anstelle des logischen OperatorsOperator typischerweise unnötige Verzweigungsbedingungen eliminieren.

Es gibt immer Ausnahmen, wie zum Beispiel, wenn eine der Bedingungen ist ein Aufruf zu einer relativ langsamen Funktion (nicht nur ein gespeicherte boolean value), zum Beispiel if ((*d == *s) && !strcmp(d,s)){ ... }

Verwandte Themen