1 vs x> = 0,是否有性能差异
我听说有一位老师放弃了这一次,从那以后一直困扰着我。 假设我们想检查整数x
是否大于或等于0.有两种方法可以检查:
if (x > -1){
//do stuff
}
和
if (x >= 0){
//do stuff
}
根据这位老师, >
会稍快,那么>=
。 在这种情况下,它是Java,但根据他的说法,这也适用于C,C ++和其他语言。 这个陈述有没有道理?
在任何现实世界中都没有区别。
让我们来看看各种编译器为不同目标生成的代码。
-O2
用于GCC, /Ox
用于MSVC, -Oh
用于IAR) 使用以下模块:
void my_puts(char const* s);
void cmp_gt(int x)
{
if (x > -1) {
my_puts("non-negative");
}
else {
my_puts("negative");
}
}
void cmp_gte(int x)
{
if (x >= 0) {
my_puts("non-negative");
}
else {
my_puts("negative");
}
}
以下是他们为比较操作生成的每一项内容:
针对ARM的MSVC 11:
// if (x > -1) {...
00000 |cmp_gt| PROC
00000 f1b0 3fff cmp r0,#0xFFFFFFFF
00004 dd05 ble |$LN2@cmp_gt|
// if (x >= 0) {...
00024 |cmp_gte| PROC
00024 2800 cmp r0,#0
00026 db05 blt |$LN2@cmp_gte|
针对x64的MSVC 11:
// if (x > -1) {...
cmp_gt PROC
00000 83 f9 ff cmp ecx, -1
00003 48 8d 0d 00 00 // speculative load of argument to my_puts()
00 00 lea rcx, OFFSET FLAT:$SG1359
0000a 7f 07 jg SHORT $LN5@cmp_gt
// if (x >= 0) {...
cmp_gte PROC
00000 85 c9 test ecx, ecx
00002 48 8d 0d 00 00 // speculative load of argument to my_puts()
00 00 lea rcx, OFFSET FLAT:$SG1367
00009 79 07 jns SHORT $LN5@cmp_gte
针对x86的MSVC 11:
// if (x > -1) {...
_cmp_gt PROC
00000 83 7c 24 04 ff cmp DWORD PTR _x$[esp-4], -1
00005 7e 0d jle SHORT $LN2@cmp_gt
// if (x >= 0) {...
_cmp_gte PROC
00000 83 7c 24 04 00 cmp DWORD PTR _x$[esp-4], 0
00005 7c 0d jl SHORT $LN2@cmp_gte
GCC 4.6.1定位到x64
// if (x > -1) {...
cmp_gt:
.seh_endprologue
test ecx, ecx
js .L2
// if (x >= 0) {...
cmp_gte:
.seh_endprologue
test ecx, ecx
js .L5
针对x86的GCC 4.6.1:
// if (x > -1) {...
_cmp_gt:
mov eax, DWORD PTR [esp+4]
test eax, eax
js L2
// if (x >= 0) {...
_cmp_gte:
mov edx, DWORD PTR [esp+4]
test edx, edx
js L5
针对ARM的GCC 4.4.1:
// if (x > -1) {...
cmp_gt:
.fnstart
.LFB0:
cmp r0, #0
blt .L8
// if (x >= 0) {...
cmp_gte:
.fnstart
.LFB1:
cmp r0, #0
blt .L2
针对ARM Cortex-M3的IAR 5.20:
// if (x > -1) {...
cmp_gt:
80B5 PUSH {R7,LR}
.... LDR.N R1,??DataTable1 ;; `?<Constant "non-negative">`
0028 CMP R0,#+0
01D4 BMI.N ??cmp_gt_0
// if (x >= 0) {...
cmp_gte:
80B5 PUSH {R7,LR}
.... LDR.N R1,??DataTable1 ;; `?<Constant "non-negative">`
0028 CMP R0,#+0
01D4 BMI.N ??cmp_gte_0
如果你仍然和我在一起,下面是在评估(x > -1)
和(x >= 0)
之间出现的任何音符的差异:
(x > -1)
MSVC目标ARM使用cmp r0,#0xFFFFFFFF
,对于(x >= 0)
cmp r0,#0
。 第一条指令的操作码长两个字节。 我想这可能会带来一些额外的时间,所以我们称这为(x >= 0)
cmp ecx, -1
对于(x > -1)
对test ecx, ecx
(x > -1)
test ecx, ecx
对于(x >= 0)
test ecx, ecx
。 第一条指令的操作码长一个字节。 我想这可能会带来一些额外的时间,所以我们称这为(x >= 0)
请注意,GCC和IAR为两种比较生成了相同的机器码(可能的例外是使用哪个寄存器)。 所以根据这项调查,似乎(x >= 0)
有一个“更快”的机会。 但是无论什么优势,最小的操作码字节编码可能会有(并且我强调可能会有)会被其他因素完全掩盖。
如果您发现Java或C#的jitted输出有任何不同,我会感到惊讶。 我怀疑你会发现任何不同的音符,即使是像8位AVR这样的非常小的目标。
总之,不要担心这种微观优化。 我认为我在这里写的已经花费了更多的时间,而不会花费在这些表达式的性能差异上,而这些表达式在我一生中执行它们的所有CPU上积累的性能有所差异。 如果您有能力测量性能差异,请将您的努力应用到更重要的事情上,如研究亚原子粒子的行为或其他内容。
它非常依赖于底层架构,但任何区别都很小。
如果有的话,我期望(x >= 0)
稍快一些,因为与某些指令集(如ARM)上的0
进行比较是免费的。
当然,任何明智的编译器都会选择最佳的实现方式,而不管源代码中包含哪个变体。
你的老师一直在阅读一些真正的旧书。 过去,一些体系结构缺乏greater than or equal
指令的评估>
所需的机器周期少于>=
,但这些平台目前很少见。 我建议去可读性,并使用>= 0
。