< 比 <= 快吗?

新手上路,请多包涵

if (a < 901)if (a <= 900) --- 快吗?

与这个简单的示例不完全一样,但循环复杂代码的性能略有变化。我想这必须与生成的机器代码有关,以防万一。

原文由 Vinícius 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 562
2 个回答

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

  • 一条 testcmp 指令,设置 EFLAGS
  • 还有一个 Jcc (jump) 指令,具体取决于比较类型(和代码布局):
  • jne - 如果不相等则跳转 –> ZF = 0
  • jz - 如果为零(等于)则跳转 –> ZF = 1
  • jg - 如果大于则跳转 –> ZF = 0 and SF = OF
  • (ETC…)

示例(为简洁而编辑)使用 $ gcc -m32 -S -masm=intel test.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:

    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:

所以两者之间的唯一区别是 jgjge 指令。两者将花费相同的时间。


我想解决没有任何迹象表明不同的跳转指令需要相同的时间的评论。这个回答有点棘手,但我可以给出以下内容:在 Intel Instruction Set Reference 中,它们都被归类在一个通用指令下, Jcc (如果满足条件则跳转)。在 优化参考手册 的附录 C. 延迟和吞吐量中进行了相同的分组。

延迟— 执行内核完成构成指令的所有 μop 的执行所需的时钟周期数。

吞吐量——在发布端口可以再次自由地接受相同指令之前需要等待的时钟周期数。对于许多指令,一条指令的吞吐量可能远低于其延迟

Jcc 的值为:

       Latency   Throughput
Jcc     N/A        0.5

Jcc 上有以下脚注:

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

因此,英特尔文档中的任何内容都没有将 Jcc 指令与其他指令区别对待。

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


编辑:浮点

这也适用于 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

原文由 Jonathon Reinhart 发布,翻译遵循 CC BY-SA 4.0 许可协议

在 C 和 C++ 中,编译器的一个重要规则是“as-if”规则:如果执行 X 与执行 Y 具有完全相同的行为,那么编译器可以自由选择它使用哪一个。

在您的情况下,“a < 901”和“a <= 900”始终具有相同的结果,因此编译器可以自由编译任一版本。如果某个版本更快,无论出于何种原因,任何高质量的编译器都会为更快的版本生成代码。因此,除非您的编译器生成异常糟糕的代码,否则两个版本将以相同的速度运行。

现在,如果您遇到两种代码总是会产生相同结果的情况,但是很难为编译器证明,和/或编译器很难证明哪个版本更快,那么您可能会得到不同的代码以不同的速度运行。

PS 如果处理器支持单字节常量(更快)和多字节常量(更慢),原始示例可能以不同的速度运行,因此与 255(1 个字节)进行比较可能比与 256(2 个字节)进行比较更快。我希望编译器能做任何更快的事情。

原文由 gnasher729 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题