我想知道这些片段中的哪一个更快。
我通常使用这个表达式:
if(x <= y)
break;
但使用它有什么好处吗?
if(!(x > y))
break;
这是我的推理。我认为第一个陈述实际上是这样的:
if(x == y)
break;
if(x < y)
break;
但我认为第二个陈述只是这个:
if(!(x > y))
break;
这让我相信第二个陈述更快。这是对的吗?
答案 0 :(得分:8)
使用gcc -O3 -march=native -m64 -fomit-frame-pointer -S
编译:
int f(int x, int y) {
if (x <= y) return 1;
return 0;
}
f:
xorl %eax, %eax
cmpl %edx, %ecx
setle %al
ret
和
int f(int x, int y) {
if (!(x > y)) return 1;
return 0;
}
f:
xorl %eax, %eax
cmpl %edx, %ecx
setle %al
ret
也就是说,对于整数,它们完全相同 - 实际上编译器优化了第二个示例到第一个,因为它更快,而不是更慢。
答案 1 :(得分:4)
编译器不太可能生成与另一个不同的东西。
几乎所有现代处理器都具有greater or equal
或less or equal
比较/分支操作,因此没有理由进行更复杂的比较。
声明
if(x == y)
if (x < y)
break;
没有任何意义。 x == y
为真,在这种情况下x < y
不成立。或x == y
为假,如果有的话,你不输入第二个。
显然,如果x
和y
是一个类,那么operator<=
可以写成:
operator<=(const A& x, const A& y)
{
if (x == y) return true;
return x < y;
}
但那会相当愚蠢,因为它也可以写成:
operator<=(const A& x, const A& y)
{
return !(x > y);
}
答案 2 :(得分:1)
假设x&amp; y是以类型构建的,
这是我的推理。我认为第一个陈述实际上是这样的:
if(x == y)
if(x < y)
break;
这是不对的。 CPU可以执行<=
次操作。不要过度优化;)
答案 3 :(得分:1)
您可以期待任何足够先进的编译器自动将这些等效语句优化到目标体系结构上最快的一个,因此在实践中它们的行为会相同。
但是当这些片段按字面解释时,在x86体系结构上第一个是单个操作,因为x86 CPU指令集既有跳转时间指令,也有跳时差或相等指令
答案 4 :(得分:1)
就int(或短或长或其他)而言,只需使用x <= y
,编译器就应对其进行优化。例如,在x86-64:
cmpq %rax, %rcx
jg false
#This is code to execute if (x <= y).
# Code
# .......
false:
#This is code to execute once the
# if statement is done or the condition
# resulted in a falsy value.
如果你有一个if-else语句,有两个跳转指令:第一个是条件产生一个假值,第二个是在代码块的末尾,当条件产生一个真值时(所以它可以跳过用于else块的代码。)
请注意,我使用了jg(如果大于跳转)指令。 x86和x86-64都有一个jnle(跳转,如果不小于或等于)指令,但它做同样的事情(毕竟,如果x不小于或等于y,那么逻辑x必须更大比y),但从ASM工作的角度来看,反转条件更有意义。如果条件没有被反转,你可以跳转到执行if语句的代码,然后向后跳转以恢复程序的主流程。为什么在两次跳跃中你可以做一次?
顺便说一句,我不是ASM大师。但是,如果您稍微使用它,它可以帮助您避免提出类似这样的问题,因为编译器应该将(x <= y)
条件优化为!(x > y)
代码,如我所示。没有必要尝试第二次猜测你的编译器。专注于您可以进行的常规优化,以帮助编译器优化您的代码,例如消除首先不需要执行的条件,而不是它已经知道如何执行的小东西。
答案 5 :(得分:0)
您应该使用<=
CPU可以对基元执行<=
操作。
如果类具有重载的运算符<=
,则可以安全地假设它已经过优化,可以比if(!(x > y))
更好或至少等于它。如果它存在,请使用它。有人出于某种原因努力实施它。