[c++] 是<快于<=?



Answers

从历史上看(我们正在谈论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

因此,在某些机器上,使用“少于”比较可能会节省一条机器指令 。 这与亚MHz速度和1:1 CPU到内存速度比的时代相关,但现在几乎完全不相关。

Question

我正在读一本书,作者说if( a < 901 )if( a <= 900 )快。

与这个简单的例子不完全一样,但是在复杂的循环代码上有轻微的性能变化。 我想这必须用生成的机器代码来做,以防万一。




其他答案都集中在x86体系结构上,我不知道ARM体系结构(您的示例汇编程序似乎是)足以对所生成的代码进行具体评论,但这是micro-optimisation一个示例,它非常适合体系结构具体而言,并且很可能是一种反优化,因为它是一种优化

因此,我认为这种micro-optimisation货物崇拜编程的一个例子,而不是最好的软件工程实践。

这可能是一些优化的架构,但我知道至少有一种架构可能是正确的。 历史悠久的Transputer体系结构只有机器代码指令等于大于或等于 ,因此所有比较必须从这些基元构建而成。

即使在那时,在几乎所有情况下,编译器都可以按照这样的方式排列评估指令,实际上,没有任何比较有任何优势。 最糟糕的情况是,它可能需要添加一个反向指令(REV)来交换操作数堆栈中的前两项。 这是一个单字节指令,需要一个周期才能运行,所以可能有最小的开销。

这样的微型优化是一种优化还是一种反优化取决于你正在使用的特定架构,所以习惯使用体系结构特定的微观优化通常是一个坏主意,否则你可能本能地如果这样做不恰当,就使用一个,看起来这就是你正在阅读的书正在倡导的。




也许这本未命名的书的作者已经读过, a > 0运行速度超过a >= 1并且认为这是普遍的。

但是这是因为涉及0 (因为CMP可以取决于体系结构,例如用OR取代)而不是因为<




他们有相同的速度。 也许在某些特殊架构中,他/她说的是对的,但在x86家族中,至少我知道它们是相同的。 因为为此,CPU将执行减法(a - b),然后检查标志寄存器的标志。 该寄存器的两位称为ZF(零标志)和SF(标志标志),并且在一个周期内完成,因为它将通过一次掩码操作完成。




我发现这两者都不是更快。 编译器在每个条件下生成具有不同值的相同机器代码。

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



你可以说在大多数脚本语言中这一行是正确的,因为额外的字符会导致代码处理速度稍慢。 但是,正如最佳答案指出的那样,它在C ++中应该没有任何作用,并且任何使用脚本语言完成的事情可能都不是关心优化。






Related