当前位置: 首页 > 知识库问答 >
问题:

x>-1 vs x>=0,是否存在性能差异

西门嘉石
2023-03-14
if (x > -1){
    //do stuff
}
if (x >= 0){
    //do stuff
} 

根据这位老师的说法,>会比>=稍微快一点。在本例中,它是Java,但据他说,这也适用于C、C++和其他语言。这种说法有道理吗?

共有1个答案

董俊
2023-03-14

在现实世界中没有任何区别。

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

>

  • 我假设一个带符号的int操作(这似乎是操作的意图)
  • 通过调查,我仅限于C和手头手头的编译器(诚然是一个相当小的示例-GCC、MSVC和IAR)
  • 已启用基本优化(-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");
        }
    }
    
    // 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|
    
    // 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:

    // 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
    
    // if (x > -1) {...
    cmp_gt:
        .fnstart
    .LFB0:
        cmp r0, #0
        blt .L8
    
    // if (x >= 0) {...
    cmp_gte:
        .fnstart
    .LFB1:
        cmp r0, #0
        blt .L2
    
    // 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
    
      null

    注意,GCC和IAR为两种比较生成了相同的机器代码(可能使用了寄存器除外)。因此,根据这项调查,(x>=0)似乎有一个非常小的“更快”的机会。但是,无论最短操作码字节编码可能有什么优势(我强调可能有什么优势),肯定会被其他因素完全掩盖。

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

    总之,不用担心这个微优化。我认为我在这里的写作已经花费了更多的时间,而这些表达式在我有生之年执行它们的所有CPU上累积的性能差异将会花费更多的时间。如果你有能力测量性能上的差异,请把你的努力用在一些更重要的事情上,比如研究亚原子粒子的行为之类的。

  •  类似资料:
    • 问题内容: 我曾经听过一位老师丢弃它,此后一直困扰着我。假设我们要检查整数是否大于或等于0。有两种检查方法: 和 据这个老师说会快一些。在这种情况下,它是Java,但据他说,这也适用于C,c ++和其他语言。这句话有什么道理吗? 问题答案: 在现实世界中没有任何区别。 让我们看一下各种编译器为各种目标生成的代码。 我假设一个有符号的int操作(这似乎是OP的意图) 通过调查,我仅限于C和我手边的编

    • 问题内容: 如果我使用Javac打开调试信息的生成,则类文件将增加20-25%。这对运行Java程序有任何性能影响吗?如果是,则在哪些条件下以及在多少条件下。我希望对加载类有一点影响,因为文件较大,但这应该很小。 问题答案: 用任何语言,调试信息都是元信息。它的性质增加了目标文件的大小,从而增加了加载时间。在调试器外部执行期间,实际上完全忽略了此信息。如JVM规范中所述(尽管不清楚),调试信息存储

    • 问题内容: 并且似乎返回相同的结果。它们之间有什么性能差异,为什么? 问题答案: deque.popleft()比list.pop(0)更快,这是因为deque已被优化以在O(1)中执行popleft(),而list.pop(0)需要O(n)(请参阅deque对象) 。 _collectionsmodule.c中用于deque的注释和代码以及listobject.c中用于list的注释和代码提供了

    • 问题内容: 以下两个循环之间的性能差异(如果有)是什么? 和 问题答案: 版本1.5中引入的for-each循环通过完全隐藏迭代器或index变量,消除了混乱和出错的机会。结果成语同样适用于集合和数组: 当你看到冒号(:)时,将其读为“ in”。因此,上面的循环读为“对于元素中的每个元素e”。请注意,即使对于数组,使用for-each循环也不会降低性能。实际上,在某些情况下,它可能只比普通的for

    • 说到“性能差异”,到目前为止,我还没有读到什么可靠的东西。 基于其官方文档,作为bool查询中使用的筛选器 子句(查询)必须出现在匹配的文档中。但是,与must不同的是,查询的分数将被忽略。筛选子句在筛选上下文中执行,这意味着计分被忽略,子句被考虑用于缓存。 至于常数分数查询 筛选查询不计算相关性得分。为了提高性能,Elasticsearch会自动缓存经常使用的筛选器查询。 QAs我刚刚读到:El

    • 在循环中,我们不断终止条件,并在每一次传递中检查这些条件。 我见过2种检查方法 1.或