【问题标题】:Which is more efficient. if(a-b >0) or if (a > b) [closed]哪个更有效率。 if(a-b >0) 或 if (a > b) [关闭]
【发布时间】:2014-08-12 10:01:48
【问题描述】:

这可能是一个简单的问题。

我想知道这 2 条语句中的哪一条将花费更少的时间来执行。

if ( a - b > 0 ) or if ( a > b )

在第一种情况下,必须计算差异,然后将其与0进行比较,而在第二种情况下,直接比较a和b。

谢谢。

【问题讨论】:

  • 与往常一样,这些微小的差异在当今的计算机上毫无意义。如果它可能很重要,它取决于你的编译器。因此,请使用分析器并找出自己的情况。
  • 这种微优化已经花费了您更多的时间来发布问题,而不是您可能通过提高性能来恢复。
  • 什么语言?哪个编译器?调用了哪些选项?两者不一定等价; a - b 可以溢出。
  • 如果目的是测试a 是否大于b,则执行if (a > b)。如果另一个更快,那么你的编译器应该为你做那个转换。

标签: algorithm performance


【解决方案1】:

为了可读性,我总是选择a > b

【讨论】:

    【解决方案2】:

    如果你真的想知道,在 C 语言中,假设我们有 test.c:

    int main()
    {
      int a = 1000, b = 2000;
      if (a > b) {
        int c = 2;
      }
      if (a - b > 0) {
        int c = 3;
      }
    }
    

    gcc -S -O0 test.c编译,得到test.s

    .file   "test.c"
    .text
    .globl  main
    .type   main, @function
    main:
    
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $1000, -16(%rbp)
        movl    $2000, -12(%rbp)
        movl    -16(%rbp), %eax
        cmpl    -12(%rbp), %eax
        jle .L2
        movl    $2, -8(%rbp)
    .L2:
        movl    -12(%rbp), %eax
        movl    -16(%rbp), %edx
        subl    %eax, %edx
        movl    %edx, %eax
        testl   %eax, %eax
        jle .L4
        movl    $3, -4(%rbp)
    .L4:
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
        .section    .note.GNU-stack,"",@progbits
    

    请看上面

        movl    $1000, -16(%rbp)
        movl    $2000, -12(%rbp)
        movl    -16(%rbp), %eax
        cmpl    -12(%rbp), %eax
        jle .L2
        movl    $2, -8(%rbp)
    

        movl    -12(%rbp), %eax
        movl    -16(%rbp), %edx
        subl    %eax, %edx
        movl    %edx, %eax
        testl   %eax, %eax
        jle .L4
        movl    $3, -4(%rbp)
    

    a - b > 0 需要多一步。

    注意

    1. 以上是在Ubuntu 14.04gcc 4.8 上编译的,优化关闭(-O0)
    2. 正如@Blastfurnace 所指出的,使用-O2-O3,汇编代码不再可读。你需要配置文件才能得到一个想法。但我相信它们会针对相同的代码进行优化。
    3. 谁在乎

    【讨论】:

    • 既然问题是关于性能的,为什么要关闭优化?
    • @Blastfurnace 使用-O2-O3,上述简单示例优化为空。实际上在我看来,-O2-O3,代码没有区别。感谢您指出这一点。
    • 为了防止优化所有内容,您可以从标准输入读取ab 并打印c。你的第三点是正确的。
    【解决方案3】:

    正如 Keith Thompson 指出的那样,两者相同。例如,如果ab 是无符号的,则a-b 始终为非负数,从而使语句等效于if(a != b)

    反正我做了一个不切实际的测试:

    int main() {
        volatile int a, b;
    
        if(a-b>=0)
            printf("a");
    
        if(a>b)
            printf("b");
    
        return  0;
    }
    

    -O3 编译它。这是反汇编:

        pushq   %rbp
    Ltmp2:
        .cfi_def_cfa_offset 16
    Ltmp3:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
    Ltmp4:
        .cfi_def_cfa_register %rbp
        subq    $16, %rsp
        movl    -4(%rbp), %eax
        subl    -8(%rbp), %eax
        testl   %eax, %eax
        jle LBB0_2
    ## BB#1:
        movl    $97, %edi
        callq   _putchar
    LBB0_2:
        movl    -4(%rbp), %eax
        cmpl    -8(%rbp), %eax
        jle LBB0_4
    ## BB#3:
        movl    $98, %edi
        callq   _putchar
    LBB0_4:
        xorl    %eax, %eax
        addq    $16, %rsp
        popq    %rbp
        ret
    

    -O3a-b>0 仍在使用一条额外的指令。

    即使你用 ARM 编译器编译,也有额外的指令:

        push    {lr}
        sub sp, sp, #12
        ldr r2, [sp, #0]
        ldr r3, [sp, #4]
        subs    r3, r2, r3
        cmp r3, #0
        ble .L2
        movs    r0, #97
        bl  putchar(PLT)
    .L2:
        ldr r2, [sp, #0]
        ldr r3, [sp, #4]
        cmp r2, r3
        ble .L3
        movs    r0, #98
        bl  putchar(PLT)
    .L3:
        movs    r0, #0
        add sp, sp, #12
        pop {pc}
    

    请注意,(1)volatile 是不现实的,除非您正在处理例如硬件寄存器或线程共享内存,以及 (2) 实践中的差异甚至无法衡量。

    由于两者在某些情况下具有不同的语义,写出正确的。以后担心优化!

    【讨论】:

      【解决方案4】:

      如果执行减法和测试符号的结果与比较结果相同并且运行速度更快,则处理器设计人员会将整数比较指令映射到减法和测试。

      我认为您可以假设比较至少与减法和测试一样快,并且具有更清晰的真正主要优势。

      【讨论】:

        猜你喜欢
        • 2016-01-13
        • 1970-01-01
        • 2018-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多