0

Are the following statements essentially the same when it comes to performance?

a = a / 10; 

or

a /= 10;
Maroun
  • 94,125
  • 30
  • 188
  • 241
gipfeli
  • 29
  • 1
  • 3
  • To your performance, the second is better :) – Maroun Apr 23 '14 at 14:17
  • 2
    Did you try and benchmark this? Or how about looking at the assembly code to see if they are the same? – crashmstr Apr 23 '14 at 14:17
  • Any decent compiler will almost certainly compile these into *precisely* the same code. – Paul Roub Apr 23 '14 at 14:17
  • @PaulRoub: Depends on `i`. Still, the second can only be worse for pathological cases of `i`. – Deduplicator Apr 23 '14 at 15:19
  • 1
    Why is this on hold? It has 5 answers and dozens of comments. It may be an odd question but obviously many people found it very clear what is being asked. – BernieP Apr 23 '14 at 16:10
  • 1
    I did some quick tests and found I could type the second one almost 23% faster. – tadman Apr 23 '14 at 18:36
  • I agree with @user1074069 this question is valid, it only could be formulated in more technical way as "How compilers threat Syntactic sugar" and `/=` could be one of examples with `?:` and `++` Such things are commonly used but nobody really cares how it's treated by compiler and how it impact on performance. – janisz Apr 23 '14 at 18:44

4 Answers4

4

It depends - for basic types, any compiler should generate the same code for both.

For user-defined types, where you can overload the two operators to do different things (please don't), it's entirely dependent on how they're implemented.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • +1 for mentioning operator overloading, because the OP did not specify a type for `a`, so it could be anything. – Bgie Apr 23 '14 at 14:28
  • +1 Should, or could often, especially if all rules for proper operator overloading are followed? – Deduplicator Apr 23 '14 at 14:36
1

It depends on the compiler. One may guess, that most compilers will generate the same code from both instructions.

Try to benchmark this code or look into assembly code, what code is being generated in each case.

For instance, Microsoft Visual Studio 2013 in debug mode:

    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  

The situation changes though if we're talking about user types, because you can implement different algorithms for these two operators. In such case performance depends strictly on specific implementation.

Spook
  • 25,318
  • 18
  • 90
  • 167
  • 1
    This is only an answer for buildin types. OP never indicated his `i` is builtin. – Deduplicator Apr 23 '14 at 14:46
  • Good point. I always forget about the fact, that you can as well add images to the report using the += operator (if one is mad enough to implement such thing and I heard, that once one was) – Spook Apr 24 '14 at 05:28
1

Lets make small test. I'm using gcc version 4.7.3

I expect that a /= 10 is equal a = a / 10. We can check it by compiling code to asm using -S parameter

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

will give

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

and

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

gives same output

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

To sum up, difference in short operation operators is only in readability but only for primitive operators. Good example of different performace is preincrement and postincrement for iterators

Community
  • 1
  • 1
janisz
  • 6,292
  • 4
  • 37
  • 70
0

In the general case, the second example is always preferable.

The reasons are very simple.

For anything other than an intrinsic data type, operator/ will (certainly should!) be implemented in terms of operator/=.

This is because operator/ takes a copy, applies operator/= (Don't Repeat Yourself) and then returns that copy.

a /= 10;

boils down to

  1. call operator/= on a

while

a = a / 10; 

boils down to:

  1. call operator/ on a, which:
  2. calls the copy constructor
  3. calls operator/= on the copy
  4. call the assignment operator to assign the returned copy into a

You will usually see the operators declared like this:

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;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142