哪个运算符更快(>或> =),(<或<=)?
是<
更便宜(快)比<=
,同样, >
更便宜(快)比>=
?
免责声明:我知道我可以测量,但这只会在我的机器上,我不确定答案可能是“具体实现”还是类似的。
它有所不同,首先从检查不同的指令集开始,以及编译器如何使用这些指令集。 以openrisc 32为例,这显然是mips的灵感,但条件不同。 对于or32有比较和置位标志指令,比较这两个寄存器如果小于或等于无符号则设置标志,比较这两个寄存器是否相等设置标志。 然后有两个条件分支指令在标志集上分支并在标志清除时分支。 编译器必须遵循这些路径之一,但少于,少于或等于,大于等等都将使用相同数量的指令,相同的执行时间用于条件分支,相同的执行时间用于不执行条件分支。
现在,对于大多数架构而言,执行分支需要比不执行分支更长的时间,这是因为必须刷新并重新填充管道。 一些分支预测等可以帮助解决这个问题。
现在一些体系结构的指令大小可能会有所不同,比较gpr0和gpr1与比较gpr0和中间数字1234,可能需要更大的指令,例如x86中会看到很多。 所以虽然这两种情况可能是一个分支,如果少于你如何编码,取决于哪些寄存器碰巧保持什么值会导致性能差异(当然,x86会做很多流水线处理,大量缓存等来弥补这些问题)。 另一个类似的例子是mips和or32,其中r0总是零,它不是一个真正的通用寄存器,如果你写它,它不会改变,它是硬连线到零,所以比较,如果等于0可能会花费你如果需要额外的指令或两个指令来填充gpr以使比较可能发生,最坏的情况是必须将寄存器驱逐到堆栈或存储器,释放注册立即在那里,以便可以发生比较。
一些体系结构会像arm一样执行条件执行,因为您可以在每个指令的基础上执行全臂(而非拇指)指令,因此如果您有代码
if(i==7) j=5; else j=9;
arm的伪代码将会是
cmp i,#7
moveq j,#5
movne j,#7
没有实际的分支,所以没有管线问题让你飞快地通过,非常快。
一个架构到另一个架构,如果这是一个有趣的比较,如上所述,mips或32,你必须专门执行某种指令的比较,其他像x86,msp430和绝大多数每个alu操作改变旗帜,手臂和像更改标志,如果你告诉它改变标志,否则不要如上所示。 所以a
while(--len)
{
//do something
}
循环1的减法还会设置标志,如果循环中的内容足够简单,则可以使整个事情有条件,因此可以节省单独的比较和分支指令,并节省流水线代价。 Mips通过比较解决了这一点,并且分支是一条指令,并且它们在分支之后执行一条指令以在管道中保存一点。
一般的答案是你不会看到差异,指令的数量,执行时间等等对于各种条件是相同的。 特殊情况下,如小立即比较大的立即数等可能会对角落案例产生影响,或者编译器可能会根据您做的比较而选择完全不同。 如果您尝试重写您的算法以使其给出相同的答案,但使用小于而不是大于等于,则可以更改代码以获得不同的指令流。 同样,如果您执行的性能测试过于简单,编译器可以/将优化比较完成并仅生成结果,这可能会因您的测试代码而异,从而导致不同的执行。 所有这些的关键是反汇编你想比较的东西,看看指令的不同之处。 这将告诉你,如果你应该期望看到任何执行差异。
TL; DR
四个操作员之间看起来几乎没有区别,因为他们都在大约相同的时间执行(在不同的系统上可能会有所不同)。 所以,如果有疑问,只需使用对情况最有意义的运算符(特别是在使用C ++时)。
所以,不要紧张,这是一个长久的解释:
假设整数比较:
就组件生成而言,结果取决于平台。 在我的电脑(Apple LLVM Compiler 4.0,x86_64)上,结果(生成的程序集如下):
a < b (uses 'setl'):
movl $10, -8(%rbp)
movl $15, -12(%rbp)
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setl %cl
andb $1, %cl
movzbl %cl, %eax
popq %rbp
ret
a <= b (uses 'setle'):
movl $10, -8(%rbp)
movl $15, -12(%rbp)
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setle %cl
andb $1, %cl
movzbl %cl, %eax
popq %rbp
ret
a > b (uses 'setg'):
movl $10, -8(%rbp)
movl $15, -12(%rbp)
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setg %cl
andb $1, %cl
movzbl %cl, %eax
popq %rbp
ret
a >= b (uses 'setge'):
movl $10, -8(%rbp)
movl $15, -12(%rbp)
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setge %cl
andb $1, %cl
movzbl %cl, %eax
popq %rbp
ret
这并没有真正地告诉我很多。 所以,我们跳到基准:
女士们,先生们,结果是,我创建了以下测试程序(我意识到“时钟”不是计算这种结果的最佳方法,但现在必须完成)。
#include <time.h>
#include <stdio.h>
#define ITERS 100000000
int v = 0;
void testL()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++) {
v = i < v;
}
printf("%s: %lun", __FUNCTION__, clock() - start);
}
void testLE()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++)
{
v = i <= v;
}
printf("%s: %lun", __FUNCTION__, clock() - start);
}
void testG()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++) {
v = i > v;
}
printf("%s: %lun", __FUNCTION__, clock() - start);
}
void testGE()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++) {
v = i >= v;
}
printf("%s: %lun", __FUNCTION__, clock() - start);
}
int main()
{
testL();
testLE();
testG();
testGE();
}
其中,在我的机器上(用-O0
编译)给了我这个(5个单独的运行):
testL: 337848 testLE: 338237 testG: 337888 testGE: 337787 testL: 337768 testLE: 338110 testG: 337406 testGE: 337926 testL: 338958 testLE: 338948 testG: 337705 testGE: 337829 testL: 339805 testLE: 339634 testG: 337413 testGE: 337900 testL: 340490 testLE: 339030 testG: 337298 testGE: 337593
我会争辩说,这些运营商之间的差异充其量是微不足道的,并且在现代计算机世界中并不占重要地位。
链接地址: http://www.djcxy.com/p/31567.html