算术运算器速度

Arithmetic operator speed

本文关键字:速度 运算器      更新时间:2023-10-16

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

a = a / 10; 

a /= 10;

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

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

让我们进行小测试。我使用的是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

总之,短运算运算符的区别仅在于可读性,而仅限于基元运算符。不同性能的一个很好的例子是迭代器的预创建和后创建

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

试着对这些代码进行基准测试,或者查看汇编代码,在每种情况下都会生成什么代码。

例如,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  

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

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

原因很简单。

对于除内部数据类型之外的任何类型,运算符/都将(当然应该!)以运算符/=的形式实现。

这是因为操作符/获取一个副本,应用操作符/=(Don't Repeat Yourself),然后返回该副本。

a /= 10;

归结为

  1. 呼叫接线员/=

a = a / 10; 

归结为:

  1. 呼叫上的操作员/,该操作员:
  2. 调用复制构造函数
  3. 呼叫副本上的操作员/=
  4. 调用赋值运算符将返回的副本赋值到

你通常会看到运营商这样声明:

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