是 (x <= y) 或 !(x > y) 更有效率?
Is (x <= y) or ! (x > y) more efficient?
我想知道这些片段中哪一个更快。
我通常使用这个表达式:
if(x <= y)
break;
但是使用这个有好处吗?
if(!(x > y))
break;
以下是我的推理。我认为第一个声明实际上是这样的:
if(x == y)
break;
if(x < y)
break;
但我认为第二种说法只是:
if(!(x > y))
break;
这使我相信第二种说法更快。这是对的吗?
使用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
也就是说,对于整数,它们完全相等——事实上,编译器将第二个例子优化为第一个例子,因为它更快,而不是更慢。
编译器不太可能生成与其他编译器不同的东西。几乎所有现代处理器都有greater or equal
或less or equal
比较/分支操作,因此没有理由进行更复杂的比较。
声明
if(x == y)
if (x < y)
break;
没有任何意义。要么x == y
为真,在这种情况下x < y
不为真。或者x == y
为false,并且根本不输入第二个if。
显然,如果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);
}
假设x&y是内置类型,
以下是我的推理。我认为第一个声明实际上是这样的:
if(x == y)
if(x < y)
break;
这是不对的。CPU可以执行<=
操作。不要过度优化;)
您可以期望任何足够高级的编译器自动优化这些等价语句,使其成为目标体系结构上最快的语句,因此在实践中它们的行为是相同的。
但是,当这些片段被字面解释时,在x86体系结构上,第一个操作将是单个操作,因为x86 CPU指令集既有在较少时跳转的指令,也有在较少或相等时跳转的指示。
就int(或short或long-long或其他)而言,只需使用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)
代码,正如我所展示的那样。没有必要对编译器进行事后猜测。专注于可以帮助编译器优化代码的常规优化,例如消除最初不需要执行的条件,而不是它已经知道如何执行的小事情。
使用<=
有两个原因
-
CPU可以对基元执行
<=
操作。 -
如果类有一个重载运算符
<=
,那么可以肯定地假设它经过了优化,比if(!(x > y))
做得更好,或者至少等于它。所以,如果它存在,就使用它。有人努力实现它是有原因的。
- EASTL矢量<向量<int>>连续的
- 在跟随中,哪个地方更有效率?
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- C 字符串比较“祝您好运”&gt;“再见”
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- 有点迂腐的问题:哪个更有效率
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- C 操作员&gt;&gt;与突变器过载
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 是否需要使用 - &gt;运算符在C 中调用成员函数时
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- 错误c++visual studio c2227左侧'->;Init';必须指向类/结构/联合/泛型类型
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- ``这个''不能用this-&gt;指针变量
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在