回答
它有所不同,首先从检查不同的指令集开始,以及编译器如何使用这些指令集。以openrisc 32为例,这显然是mips的灵感,但条件不同。对于or32有比较和置位标志指令,比较这两个寄存器如果小于或等于无符号则设置标志,比较这两个寄存器是否相等设置标志。然后有两个条件分支指令在标志集上分支并在标志清除时分支。编译器必须遵循这些路径之一,但少于,少于或等于,大于等等都将使用相同数量的指令,相同的执行时间用于条件分支,相同的执行时间用于不执行条件分支。
现在,对于大多数架构来说,执行分支需要比不执行分支更长的时间,因为必须刷新并重新填充管道。一些分支预测等可以帮助解决这个问题。
现在一些体系结构的指令大小可能会有所不同,比较gpr0和gpr1与比较gpr0和立即数1234,可能需要更大的指令,例如x86中会看到很多。所以虽然这两种情况可能是一个分支,如果少于你如何编码,取决于哪些寄存器碰巧保持什么值会导致性能差异(当然,x86会做很多流水线处理,大量缓存等来弥补这些问题)。另一个类似的例子是mips和or32,其中r0总是零,它不是一个真正的通用寄存器,如果你写它,它不会改变,它是硬连线到零,所以比较,如果等于0可能会花费你如果需要额外的指令或两个指令来填充gpr以使比较可能发生,最坏的情况是必须将寄存器驱逐到堆栈或存储器,释放注册立即在那里,以便可以发生比较。
某些架构,条件执行像手臂,为全面臂(未拇指)的指令,你可以在每个指令的基础上执行的,所以如果你有代码
if(i==7) j=5; else j=9;
对手臂的伪代码将是
cmp i,#7
moveq j,#5
movne j,#7
没有实际的分支,所以没有管道问题你飞轮通过,非常快。
一个体系结构到另一个如果这是一个有趣的比较一些提到的,mips或32,你必须专门执行某种比较的指令,其他像x86,msp430和绝大多数每个alu操作改变标志,手臂等改变标志,如果你告诉它改变标志,否则不要如上所示。所以
while(--len)
{
//do something
}
环1减法还设置了标志,如果在循环中的东西是很简单的,你可以使整个事情的条件,因此可以节省您的独立的比较和分支指令并且您在保存管道罚款。 Mips通过比较解决了这一点,并且分支是一条指令,并且它们在分支之后执行一条指令以在管道中保存一点。
一般的答案是你不会看到差异,指令的数量,执行时间等等对于各种条件是相同的。特殊情况下,如小立即比较大的立即数等可能会对角落案例产生影响,或者编译器可能会根据您做的比较而选择完全不同。如果您尝试重写您的算法以使其给出相同的答案,但使用小于而不是大于等于,则可以更改代码以获得不同的指令流。同样,如果您执行的性能测试过于简单,编译器可以/将优化比较完成并仅生成结果,这可能会因您的测试代码而异,从而导致不同的执行。所有这些的关键是反汇编你想比较的东西,看看指令的不同之处。这将告诉你,如果你应该期望看到任何执行差异。
TL; DR
似乎有小到无的四大运营商之间的差异,因为它们都执行大约在同一时间,我(可能在不同的系统,不同的!)。所以,如果有疑问,只需使用对情况最有意义的运算符(特别是在使用C++时)。
所以,事不宜迟,这里是长的解释:
假设整数比较:
至于组件产生,结果是依赖于平台。在我的电脑公司(Apple LLVM编译器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: %lu\n", __FUNCTION__, clock() - start);
}
void testLE()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++)
{
v = i <= v;
}
printf("%s: %lu\n", __FUNCTION__, clock() - start);
}
void testG()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++) {
v = i > v;
}
printf("%s: %lu\n", __FUNCTION__, clock() - start);
}
void testGE()
{
clock_t start = clock();
v = 0;
for (int i = 0; i < ITERS; i++) {
v = i >= v;
}
printf("%s: %lu\n", __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
我认为,这些运营商之间的差异是次要的,在最好的,不要在现代计算机世界中不占重要地位。
汇编代码实际上告诉了很多。这是说,所有这些片段必须完全相同,所有情况都是平等的。 'setcc'需要1个周期(P4除外,需要3个周期),而不管cc是什么。但这又如何相关?比较运算符几乎从不以这种方式使用 - 比较'jcc'的性能(不管cc是什么)似乎更合理。 – harold 2012-08-01 17:15:53
我第二@harold。程序集讲述了很多 - 所有的比较都是使用相同的'cmpl'指令完成的,它比较了它的参数。基本上它从第一个参数中减去第二个参数(丢弃结果),ALU设置标志寄存器中的相应位。然后可以对这些进行测试,根据或用于设置内存/寄存器值。 – 2012-08-01 18:17:26
@harold他大概的意思是“它不会告诉_me_多” – hirschhornsalz 2012-08-01 18:43:33
- 1. 哪一个是更快的字符串[]或列表<string>
- 2. 哪个.NET集合更快:枚举foreach Dictionary <>。Values或List <>?
- 3. C++ << >>运算符
- 4. >><<和运算符重载
- 5. C++重载运算符<<和运算符>>
- 6. 哪个布尔更快? <或<=
- 7. <script>或<noscript>?
- 8. QList <QString>运算符<<
- 9. 哪个更好:<脚本类型= “文/ JavaScript的”> ...</script>或<script> ...</script>
- 10. 哪一个更快/更高效:Dictionary <字符串,对象>或字典<enum,object>?
- 11. 定义布尔逻辑运算符(V,^,异或, - >,<->)
- 12. <Provider /> outside或<Router /> outside>?
- 13. 要使用哪个Seam组件:<h:outputLink>或<h:commandLink>?
- 14. PHP运算符<>
- 15. C++运算符“<" and ">”
- 16. 在<head>,其中第一个:<meta>或<title>?
- 17. 如</p> <p><code><p>This is text </p></code>或<code><div></code>或<code>This is text</code></p> <p>使用<code>XmlPullParser</code>检索URL
- 18. SortedDictionary <>或(Dictionary <> Manual Sort)
- 19. LINQ:选择<contition>或<condition>
- 20. 不能#include <QQuickView>(或<QtQuick>)。
- 21. ObjectQuery <T>或IQueryable <T>
- 22. System.config()调用<head>或<body>?
- 23. 'for'vs.'in' - 哪个更快?</p> <pre><code>if "foo" in a_list: do stuff </code></pre> <p>它是:
- 24. 返回向量<Foo>或shared_ptr <vector<Foo>>?
- 25. 运算符>>和<<在处理中的含义
- 26. 如何在DATETIME字段中使用BETWEEN或<,>运算符
- 27. 查询不识别'>'或'<'运算符
- 28. 更快:新的矢量。 <T>或向量。 <T> .splice(0,Vector。<T> .length)?
- 29. .Net XmlTextWriter:防止替换>或<与>或<
- 30. 使用指向其结构或结构本身的指针来分配内存会更好吗?</p> <pre><code>Date *ptrdate = malloc(12 * sizeof(*ptrdate)); </code></pre> <p><strong>问:</strong>哪一个更好,为什么
我猜想他们在大多数架构中都可以编译成单一指令,但答案是:谁在乎? – meagar 2012-08-01 16:17:50
它们在生成汇编指令方面几乎相同,如果这就是您要求的。 – 2012-08-01 16:18:04
我明白你的问题背后的精神,但是:你是出于学术兴趣问这个问题,还是因为你认为这可能会影响你的应用的性能?它不会。如果存在的话,这个差异绝对会被你的应用中的其他因素所淹没**。不是2或10倍,而是1m或更多。我敢打赌你根本无法衡量它。 – 2012-08-01 16:19:38