if(a<901)是否比if(a<=900)快?
与这个简单示例中的情况不同,但循环复杂代码的性能略有变化。我想这需要对生成的机器代码进行一些处理,以防它是真的。
if(a<901)是否比if(a<=900)快?
与这个简单示例中的情况不同,但循环复杂代码的性能略有变化。我想这需要对生成的机器代码进行一些处理,以防它是真的。
当前回答
至少,如果这是真的,编译器可以轻松地优化a<=b到!(a>b),因此,即使比较本身实际上较慢,但除了最简单的编译器之外,您也不会注意到差异。
其他回答
TL;DR答案
对于架构、编译器和语言的大多数组合,<不会比<=快。
完整答案
其他答案都集中在x86架构上,我不太了解ARM架构(您的示例汇编程序似乎是这样),无法对生成的代码进行具体评论,但这是一个非常特定于架构的微优化示例,很可能是反优化,也可能是优化。
因此,我认为这种微优化是货物崇拜编程的一个例子,而不是最佳软件工程实践。
反例
可能有一些架构是优化的,但我知道至少有一种架构可能是相反的。古老的Transputer体系结构只有等于和大于或等于的机器代码指令,因此所有比较都必须从这些原语构建。
即使如此,在几乎所有的情况下,编译器都可以以这样的方式对求值指令进行排序,即在实践中,没有任何比较比任何其他比较都有任何优势。但最坏的情况是,它可能需要添加反向指令(REV)来交换操作数堆栈上的前两项。这是一个单字节指令,它需要一个周期才能运行,因此开销最小。
总结
像这样的微优化是优化还是反优化取决于您正在使用的特定架构,因此养成使用特定架构的微优化的习惯通常是一个坏主意,否则您可能会在不合适时本能地使用微优化,看起来这正是您正在阅读的书所倡导的。
它们的速度相同。也许在某些特殊的架构中,他/她所说的是对的,但在x86家族中,至少我知道他们是一样的。因为为此,CPU将执行一个减法(a-b),然后检查标志寄存器的标志。该寄存器的两位被称为ZF(零标志)和SF(符号标志),它在一个周期内完成,因为它将通过一个掩码操作完成。
从历史上看(我们所说的是20世纪80年代和90年代初),有些架构是这样的。根本问题是整数比较本质上是通过整数减法实现的。这导致了以下情况。
Comparison Subtraction
---------- -----------
A < B --> A - B < 0
A = B --> A - B = 0
A > B --> A - B > 0
现在,当A<B时,减法必须借用高位才能正确进行减法,就像你用手进行加法和减法时一样。这个“借用”位通常被称为进位位,可以通过分支指令进行测试。如果减法等于零,则将设置第二位,称为零位,这意味着相等。
通常至少有两条条件分支指令,一条在进位位上分支,另一条在零位上分支。
现在,为了了解问题的核心,让我们扩展上一个表,以包括进位和零位结果。
Comparison Subtraction Carry Bit Zero Bit
---------- ----------- --------- --------
A < B --> A - B < 0 0 0
A = B --> A - B = 0 1 1
A > B --> A - B > 0 1 0
因此,实现a<B的分支可以在一条指令中完成,因为进位位仅在这种情况下是清除的,即,
;; Implementation of "if (A < B) goto address;"
cmp A, B ;; compare A to B
bcz address ;; Branch if Carry is Zero to the new address
但是,如果我们想进行小于或等于的比较,我们需要对零标志进行额外的检查,以捕捉相等的情况。
;; Implementation of "if (A <= B) goto address;"
cmp A, B ;; compare A to B
bcz address ;; branch if A < B
bzs address ;; also, Branch if the Zero bit is Set
因此,在某些机器上,使用“小于”比较可能会节省一条机器指令。这在亚兆赫处理器速度和1:1 CPU与内存速度比的时代是相关的,但在今天几乎完全不相关。
我认为两者都不快。编译器在每个条件下生成具有不同值的相同机器代码。
if(a < 901)
cmpl $900, -4(%rbp)
jg .L2
if(a <=901)
cmpl $901, -4(%rbp)
jg .L3
我的示例if来自Linux上x86_64平台上的GCC。
编译器编写者是非常聪明的人,他们认为这些事情以及我们大多数人认为理所当然的其他事情。
我注意到,如果它不是常数,那么在这两种情况下都会生成相同的机器代码。
int b;
if(a < b)
cmpl -4(%rbp), %eax
jge .L2
if(a <=b)
cmpl -4(%rbp), %eax
jg .L3
假设我们讨论的是内部整数类型,不可能一个比另一个更快。它们显然在语义上是相同的。它们都要求编译器做完全相同的事情。只有一个严重损坏的编译器才能为其中一个生成劣质代码。
如果在某些平台上,对于简单整数类型,<比<=快,编译器应始终将常量的<=转换为<。任何没有这样做的编译器都将是一个糟糕的编译器(对于该平台)。