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

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


当前回答

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

其他回答

即使有差异,你也不应该注意到。此外,在实践中,除非你要使用一些神奇的常数,否则你必须做一个额外的a+1或a-1来使条件成立,这无论如何都是一个非常糟糕的实践。

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

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

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次的像素,它将导致延迟,但与<=使用概率的重合度太低。

从历史上看(我们所说的是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