算术运算速度

时间:2014-04-23 14:15:29

标签: c++ assignment-operator

以下语句在性能方面基本相同吗?

a = a / 10; 

a /= 10;

4 个答案:

答案 0 :(得分:4)

这取决于 - 对于基本类型,任何编译器都应为两者生成相同的代码。

对于用户定义的类型,您可以重载两个运算符以执行不同的操作(请不要),这完全取决于它们的实现方式。

答案 1 :(得分:1)

这取决于编译器。可能猜测,大多数编译器将从两个指令生成相同的代码。

尝试对此代码进行基准测试或查看汇编代码,在每种情况下生成什么代码。

例如,Microsoft Visual Studio 2013处于调试模式:

    i = i / 20;
011F43C5  mov         eax,dword ptr [i]  
011F43C8  cdq  
011F43C9  mov         ecx,14h  
011F43CE  idiv        eax,ecx  
011F43D0  mov         dword ptr [i],eax  
    i /= 20;
011F43D3  mov         eax,dword ptr [i]  
011F43D6  cdq  
011F43D7  mov         ecx,14h  
011F43DC  idiv        eax,ecx  
011F43DE  mov         dword ptr [i],eax  

如果我们讨论用户类型,情况会发生变化,因为您可以为这两个运算符实现不同的算法。在这种情况下,性能严格取决于具体实施。

答案 2 :(得分:1)

让我们进行小测试。我使用的是gcc 4.7.3版本。

我希望a /= 10等于a = a / 10。我们可以通过使用-S参数

将代码编译为asm来检查它
int main() {
    int a;
    a = a / 10;
}

将给出

main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    -4(%rbp), %ecx
        movl    $1717986919, %edx
        movl    %ecx, %eax
        imull   %edx
        sarl    $2, %edx
        movl    %ecx, %eax
        sarl    $31, %eax
        movl    %edx, %ecx
        subl    %eax, %ecx
        movl    %ecx, %eax
        movl    %eax, -4(%rbp)
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

int main() {
    int a;
    a /= 10;
}

给出相同的输出

main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    -4(%rbp), %ecx
        movl    $1717986919, %edx
        movl    %ecx, %eax
        imull   %edx
        sarl    $2, %edx
        movl    %ecx, %eax
        sarl    $31, %eax
        movl    %edx, %ecx
        subl    %eax, %ecx
        movl    %ecx, %eax
        movl    %eax, -4(%rbp)
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

总而言之,短操作运算符的差异仅在于可读性,而仅适用于原始运算符。不同性能的好例子是preincrement and postincrement for iterators

答案 3 :(得分:0)

在一般情况下,第二个例子总是更可取。

原因很简单。

对于除内在数据类型之外的任何内容,operator / will(当然应该!)以operator /=实现。

这是因为operator /需要复制,应用operator / =(不要重复自己),然后返回该副本。

a /= 10;

归结为

  1. 上调用operator / =

    ,而

    a = a / 10; 
    

    归结为:

    1. 调用operator / on a,其中:
    2. 调用复制构造函数
    3. 在副本上调用operator / =
    4. 调用赋值运算符以将返回的副本分配到
    5. 您通常会看到如下所示的运算符:

      class A {
      ...
      public:
        A& operator/=(double rhs) {
          _internalThing /= rhs;
          return *this;
        }
      private:
        double _internalThing;
      };
      
      // binary operators should be free functions
      A operator/(A lhs, double rhs) {
        lhs /= rhs;
        return lhs;
      }