是否存在性能差异

是否存在性能差异

本文介绍了x> -1 vs x> = 0,是否存在性能差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我听过一个老师放下这一次,自那以后它一直在欺骗我。假设我们要检查整数 x 是否大于或等于0.有两种方法可以检查:

I have heard a teacher drop this once, and it has been bugging me ever since. Let's say we want to check if the integer x is bigger than or equal to 0. There are two ways to check this:

if (x > -1){
    //do stuff
}

if (x >= 0){
    //do stuff
}

根据这位老师 > 会稍快于> = 。在这种情况下,它是Java,但根据他也申请了C,C ++和其他语言。

According to this teacher > would be slightly faster then >=. In this case it was Java, but according to him this also applied for C, c++ and other languages. Is there any truth to this statement?

推荐答案

在任何真实世界的意义上没有区别。

There's no difference in any real-world sense.

让我们来看看各种编译器为各种目标生成的代码。

Let's take a look at some code generated by various compilers for various targets.


  • (这似乎是OP的意图)

  • 我已经通过调查限制到C和编译器,我很容易在手(不可否认,一个很小的样本 - GCC,MSVC和IAR)

  • 启用基本优化( -O2 适用于GCC, / Ox for MSVC, -Oh for IAR)

  • 使用以下模块:

  • I'm assuming a signed int operation (which seem the intent of the OP)
  • I've limited by survey to C and to compilers that I have readily at hand (admittedly a pretty small sample - GCC, MSVC and IAR)
  • basic optimizations enabled (-O2 for GCC, /Ox for MSVC, -Oh for IAR)
  • using the following module:

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");
    }
}


MSVC 11针对ARM:

MSVC 11 targeting ARM:

// 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|

MSVC 11定位x64:

MSVC 11 targeting x64:

// 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

MSVC 11定位x86:

MSVC 11 targeting x86:

// 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

GCC 4.6.1 targeting 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

GCC 4.6.1指定x86:

GCC 4.6.1 targeting x86:

// 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

GCC 4.4.1瞄准ARM:

GCC 4.4.1 targeting ARM:

// if (x > -1) {...
cmp_gt:
    .fnstart
.LFB0:
    cmp r0, #0
    blt .L8

// if (x >= 0) {...
cmp_gte:
    .fnstart
.LFB1:
    cmp r0, #0
    blt .L2

IAR 5.20针对ARM Cortex-M3 :

IAR 5.20 targeting an ARM Cortex-M3:

// 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)

If you're still with me, here are the differences of any note between evaluating (x > -1) and (x >= 0) that show up:


  • MSVC定位ARM使用 cmp r0,#0xFFFFFFFF (x> -1) vs cmp r0 ,#0 (x> = 0)。第一条指令的操作码长两个字节。我想这可能会引入一些额外的时间,所以我们将这称为(x> = 0)的优势

  • MSVC定位x86使用 cmp ecx,-1 替换(x> -1) vs ecx,ecx (x> = 0)。第一条指令的操作码长一个字节。我想这可能会引入一些额外的时间,所以我们将这称为(x> = 0)

  • MSVC targeting ARM uses cmp r0,#0xFFFFFFFF for (x > -1) vs cmp r0,#0 for (x >= 0). The first instruction's opcode is two bytes longer. I suppose that may introduce some additional time, so we'll call this an advantage for (x >= 0)
  • MSVC targeting x86 uses cmp ecx, -1 for (x > -1) vs test ecx, ecx for (x >= 0). The first instruction's opcode is one byte longer. I suppose that may introduce some additional time, so we'll call this an advantage for (x >= 0)

请注意,GCC和IAR生成相同的机器代码用于两种比较(可能的例外是使用了哪个寄存器)。因此,根据该调查,看起来(x> = 0)具有更快的非常轻微的机会。但是无论什么优势,最小的较短的操作码字节编码可能(和我强调可能具有)将肯定完全被其他因素遮蔽。

Note that GCC and IAR generated identical machine code for the two kinds of comparison (with the possible exception of which register was used). So according to this survey, it appears that (x >= 0) has an ever-so-slight chance of being 'faster'. But whatever advantage the minimally shorter opcode byte encoding might have (and I stress might have) will be certainly completely overshadowed by other factors.

如果你发现Java或C#的jorts输出有什么不同,我会很惊讶。我怀疑你会发现任何差异,即使对于一个非常小的目标,如8位AVR。

I'd be surprised if you found anything different for the jitted output of Java or C#. I doubt you'd find any difference of note even for a very small target like an 8 bit AVR.

总之,不要担心这种微优化。我认为我的写在这里已经花费了更多的时间,而不是在这些表达式的性能积累的所有CPU在我的生命中执行它们所花费的时间。如果你有能力测量性能差异,请将你的努力应用到更重要的事情,如研究亚原子粒子或某物的行为。

In short, don't worry about this micro-optimization. I think my write up here has already spent more time than will be spent by any difference in the performance of these expressions accumulated across all the CPUs executing them in my lifetime. If you have the capability to measure the difference in performance, please apply your efforts to something more important like studying the behavior of sub-atomic particles or something.

这篇关于x&gt; -1 vs x> = 0,是否存在性能差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 12:37