if(a<901)是否比if(a<=900)快?

与这个简单示例中的情况不同,但循环复杂代码的性能略有变化。我想这需要对生成的机器代码进行一些处理,以防它是真的。


当前回答

假设我们讨论的是内部整数类型,不可能一个比另一个更快。它们显然在语义上是相同的。它们都要求编译器做完全相同的事情。只有一个严重损坏的编译器才能为其中一个生成劣质代码。

如果在某些平台上,对于简单整数类型,<比<=快,编译器应始终将常量的<=转换为<。任何没有这样做的编译器都将是一个糟糕的编译器(对于该平台)。

其他回答

也许那本无名书的作者读到a>0比a>=1跑得更快,并认为这是普遍正确的。

但这是因为涉及0(因为CMP可以根据体系结构,例如用OR替换),而不是因为<。

不,它在大多数架构上不会更快。您没有指定,但在x86上,所有的积分比较通常将在两个机器指令中实现:

测试或cmp指令,用于设置EFLAGS以及Jcc(跳转)指令,具体取决于比较类型(和代码布局):jne-如果不等于-->ZF=0,则跳转jz-如果零(等于)-->ZF=1则跳转jg-如果大于-->ZF=0且SF=OF,则跳转(等等)


示例(为简洁起见编辑)使用$gcc-m32-S-masm=inteltest.c编译

    if (a < b) {
        // Do something 1
    }

编译到:

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jge     .L2                          ; jump if a is >= b
    ; Do something 1
.L2:

And

    if (a <= b) {
        // Do something 2
    }

编译到:

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jg      .L5                          ; jump if a is > b
    ; Do something 2
.L5:

因此,两者之间的唯一区别是jg与jge指令。这两者将花费相同的时间。


我想指出的是,没有任何东西表明不同的跳转指令需要相同的时间。这个问题回答起来有点棘手,但我可以给出以下答案:在“英特尔指令集参考”中,它们都被分组在一条公共指令Jcc(如果满足条件则跳转)下。根据附录C中的《优化参考手册》进行了相同的分组。延迟和吞吐量。

Latency—执行核心,以完成形成的所有μ操作的执行指令。

吞吐量—需要的时钟周期数等待发出端口可以接受相同的指令再一次对于许多指令,指令的吞吐量可以是显著低于其延迟

Jcc的值为:

      Latency   Throughput
Jcc     N/A        0.5

Jcc上有以下脚注:

条件跳转指令的选择应基于第3.4.1节“分支预测优化”的建议,以提高分支的可预测性。当成功预测分支时,jcc的延迟实际上为零。

因此,在英特尔文档中,对一条Jcc指令的处理方式与其他指令没有任何区别。

如果考虑用于实现指令的实际电路,可以假设EFLAGS中的不同位上有简单的“与/或”门,以确定是否满足条件。因此,没有理由让一条测试两个位的指令比只测试一个位花费更多或更少的时间(忽略比时钟周期短得多的门传播延迟)


编辑:浮点

x87浮点也是如此:(与上面的代码几乎相同,但使用double而不是int。)

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; Compare ST(0) and ST(1), and set CF, PF, ZF in EFLAGS
        fstp    st(0)
        seta    al                     ; Set al if above (CF=0 and ZF=0).
        test    al, al
        je      .L2
        ; Do something 1
.L2:

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; (same thing as above)
        fstp    st(0)
        setae   al                     ; Set al if above or equal (CF=0).
        test    al, al
        je      .L5
        ; Do something 2
.L5:
        leave
        ret

这将高度依赖于C编译到的底层架构。某些处理器和架构可能具有等于或小于等于的显式指令,这些指令以不同的周期执行。

但这很不寻常,因为编译器可以绕过它,使它变得无关紧要。

仅当计算路径依赖于数据时:

a={1,1,1,1,1000,1,1,1,1}
while (i<=4)
{
     for(j from 0 to a[i]){ do_work(); }
     i++;
}

将计算250倍以上的时间(i<4)

真实世界的例子是计算曼德布洛特集合。如果包含一个迭代1000000次的像素,它将导致延迟,但与<=使用概率的重合度太低。

您可以说这行在大多数脚本语言中都是正确的,因为额外的字符会导致代码处理稍慢。然而,正如上面的答案所指出的,它在C++中应该没有任何影响,而使用脚本语言所做的任何事情都可能不太关心优化。