if(a<901)是否比if(a<=900)快?
与这个简单示例中的情况不同,但循环复杂代码的性能略有变化。我想这需要对生成的机器代码进行一些处理,以防它是真的。
if(a<901)是否比if(a<=900)快?
与这个简单示例中的情况不同,但循环复杂代码的性能略有变化。我想这需要对生成的机器代码进行一些处理,以防它是真的。
当前回答
从历史上看(我们所说的是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与内存速度比的时代是相关的,但在今天几乎完全不相关。
其他回答
仅当计算路径依赖于数据时:
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次的像素,它将导致延迟,但与<=使用概率的重合度太低。
也许那本无名书的作者读到a>0比a>=1跑得更快,并认为这是普遍正确的。
但这是因为涉及0(因为CMP可以根据体系结构,例如用OR替换),而不是因为<。
至少,如果这是真的,编译器可以轻松地优化a<=b到!(a>b),因此,即使比较本身实际上较慢,但除了最简单的编译器之外,您也不会注意到差异。
对于浮点代码,甚至在现代体系结构上,<=比较可能确实会慢一些(一条指令)。这是第一个函数:
int compare_strict(double a, double b) { return a < b; }
在PowerPC上,首先执行浮点比较(更新条件寄存器cr),然后将条件寄存器移动到GPR,将“比较小于”位移位到位,然后返回。它需要四个指令。
现在考虑一下这个函数:
int compare_loose(double a, double b) { return a <= b; }
这需要与上面的compare_strict相同的工作,但现在有两个有趣的位:“小于”和“等于”。这需要一个额外的指令(cror-condition寄存器逐位OR)将这两个位组合为一。因此,compare_sloose需要五条指令,而compare_sstrict需要四条指令。
您可能认为编译器可以这样优化第二个函数:
int compare_loose(double a, double b) { return ! (a > b); }
然而,这将错误地处理NaN。NaN1<=NaN2和NaN1>NaN2都需要评估为假。
它们的速度相同。也许在某些特殊的架构中,他/她所说的是对的,但在x86家族中,至少我知道他们是一样的。因为为此,CPU将执行一个减法(a-b),然后检查标志寄存器的标志。该寄存器的两位被称为ZF(零标志)和SF(符号标志),它在一个周期内完成,因为它将通过一个掩码操作完成。