V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nyanyh
V2EX  ›  C++

-a 和 0-a 有什么区别?

  •  1
     
  •   nyanyh · 2020-04-29 20:50:01 +08:00 · 2791 次点击
    这是一个创建于 1702 天前的主题,其中的信息可能已经有所发展或是发生改变。

    认识的一位技术人员告诉我用 0-a 替换-a,可以提升性能,我将信将疑,写了小代码测试一下

    int main() {
        int a = 100;
    
        auto a1 = -a;
        auto a2 = 0-a;
    
        return 0;
    }
    

    然后看看 LLVM 的中间码

    %6:gr32 = SUB32rm %0:gr32(tied-def 0), %stack.1, 1, $noreg, 0, $noreg, implicit-def $eflags, debug-location !19 :: (load 4 from %ir.2); ./test.cpp:5:15
      MOV32mr %stack.2, 1, $noreg, 0, $noreg, killed %6:gr32, debug-location !17 :: (store 4 into %ir.3); ./test.cpp:5:10
    
      %3:gr32 = SUB32rm %0:gr32(tied-def 0), %stack.1, 1, $noreg, 0, $noreg, implicit-def $eflags, debug-location !23 :: (load 4 from %ir.2); ./test.cpp:6:16
      MOV32mr %stack.3, 1, $noreg, 0, $noreg, killed %3:gr32, debug-location !21 :: (store 4 into %ir.4); ./test.cpp:6:10
    

    是完全一样的

    再试试如果 a 是 double 呢?

    int main() {
        double a = 100;
    
        auto a1 = -a;
        auto a2 = 0-a;
    
        return 0;
    }
    

    出现了明显不同:

      %11:fr64 = MOVSDrm_alt %stack.1, 1, $noreg, 0, $noreg, debug-location !19 :: (load 8 from %ir.2); ./test.cpp:5:16
      %7:gr64 = MOVSDto64rr killed %11:fr64, debug-location !20; ./test.cpp:5:15
      %8:gr64 = MOV64ri -9223372036854775808, debug-location !20; ./test.cpp:5:15
      %9:gr64 = XOR64rr killed %7:gr64(tied-def 0), %8:gr64, implicit-def $eflags, debug-location !20; ./test.cpp:5:15
      %10:fr64 = MOV64toSDrr killed %9:gr64, debug-location !20; ./test.cpp:5:15
      MOVSDmr %stack.2, 1, $noreg, 0, $noreg, killed %10:fr64, debug-location !18 :: (store 8 into %ir.3); ./test.cpp:5:10
    
      %2:fr64 = FsFLD0SD debug-location !24; ./test.cpp:6:16
      %4:fr64 = SUBSDrm %2:fr64(tied-def 0), %stack.1, 1, $noreg, 0, $noreg, debug-location !24 :: (load 8 from %ir.2); ./test.cpp:6:16
      MOVSDmr %stack.3, 1, $noreg, 0, $noreg, killed %4:fr64, debug-location !22 :: (store 8 into %ir.4); ./test.cpp:6:10
      $eax = COPY %0:gr32, debug-location !25; ./test.cpp:8:5
    

    上面的代码都是用-O0测试的,打开优化的话就测试不出了,两行代码直接被优化掉了

    所以在某些情况下确实 0-a 比-a 少几条指令,所以会快一些?

    5 条回复    2020-04-30 15:26:18 +08:00
    xcstream
        1
    xcstream  
       2020-04-29 21:00:57 +08:00
    一个是减法 一个直接取反
    msg7086
        2
    msg7086  
       2020-04-30 08:47:56 +08:00
    测优化后代码的话可以在后面接一个 printf 打印出来。
    大部分情况应该都是能优化掉的,浮点数因为涉及到 rounding error 所以少数操作可能不会给你优化。
    (比如浮点下 a+b+c+d 和(a+b)+(c+d)的结果是不同的。而且理论上后者比前者快。)
    msg7086
        3
    msg7086  
       2020-04-30 08:56:24 +08:00   ❤️ 2
    https://godbolt.org/z/RYVwp7

    意料之中,浮点数减法调用的是 sub,而浮点数取反则是和 -0.0 取异或。
    galileo1214
        4
    galileo1214  
       2020-04-30 12:11:28 +08:00
    学到了
    fgwmlhdkkkw
        5
    fgwmlhdkkkw  
       2020-04-30 15:26:18 +08:00
    @msg7086 还有这样的网站!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2453 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 16:01 · PVG 00:01 · LAX 08:01 · JFK 11:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.