嵌套if和条件

时间:2017-03-27 13:48:33

标签: algorithm if-statement optimization

之间最有效的选择是什么:

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

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

最佳选择是什么?为什么?这取决于语言吗?

编辑这不是关于代码质量的问题。

3 个答案:

答案 0 :(得分:4)

当你尝试它时发生了什么,为什么你会期望编译器产生什么有任何区别?你的算法在两者之间没有区别。

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
好吧,好吧这很难看,但仅仅是因为我编写测试的方法,如果这些是其中之一,但两者都没有,那么编译器就会清楚地生成相同的代码。因此,对此进行测量性能测试可能会显示出差异,如果您能够看到它,但这是一个糟糕的测试。

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

另一个指令集。

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

不同的编译器

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

另一个目标与其他编译器

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

即使没有优化我也得到了同样的结果。两者之间没有区别,为什么编译器会产生差异,这可能是性能差异?

答案 1 :(得分:2)

如果您有类似的东西,最好的方法是避免使用箭头代码:

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

您还可以将所有条件抛入另一个函数并使用它:

&&

它使您的代码清晰可读,减少缩进量,使结构变平。

修改

表现更好的方法理论上是带有&&语句的表单。为什么?因为它不分支而且很懒惰。 if语句也有点懒惰,但它们分支。

但这不一定是必须的。您必须考虑branch prediction,这可能会忽略其中一些if语句,并且可能会更频繁地在if运算符处中断(只省略一个if语句会更容易)。也许编译器可能会进行一些优化,这可能会导致这两种{{1}}情况都会产生相同的汇编或字节代码。

所以基本上 - 很难说哪个具有更好的性能,因为在编译器优化甚至CPU架构的幕后发生的魔力。

如果您需要一些过早的优化教程,我建议您this预订:)

答案 2 :(得分:1)

编译代码中的短路&&和嵌套if之间几乎没有区别,但仍有一些方法可以优化这种情况。这取决于每种情况的可能性。这可以通过配置文件引导优化来确定,或者您可以尝试并凭经验确定统计信息。

如果每个布尔条件具有相同的近似似然,那么顺序并不重要;但是,如果一个或多个人有更大的机会被假,那么他们应该被命令从最可能是假的,最有可能是真的。如果所有这些都很可能是真的(将所有概率乘以真收率&gt; = 0.5)那么使用按位&运算符而不是逻辑&&运算符将消除通常不必要的分支条件

总会有例外情况,比如其中一个条件是调用相对较慢的函数(而不仅仅是存储的布尔值),例如if ((*d == *s) && !strcmp(d,s)){ ... }