1

Which is the best method for increasing a counter (integer) in java. I am interested in the cost of the operation.

int j = 0;
j = j + 1;

or

int i = 0;
i++;

It gives almost the same for small programs, but it differs for big calculations, the thousands of iterations.

tshepang
  • 12,111
  • 21
  • 91
  • 136
  • 3
    With nearly any compiler, these are going to be identical. – chrylis -cautiouslyoptimistic- Mar 08 '14 at 07:07
  • 1
    for C++ ++i is faster than i++, not sure about Java... – Maxim Mar 08 '14 at 07:10
  • You left out `++j`, which, although usually optimized by the compiler, is preferred if you *don't* need the prior value, as it eliminates the *potential* for a non-elided temp to be used. – WhozCraig Mar 08 '14 at 07:11
  • 2
    In Java, the performance is the same. – Peter Lawrey Mar 08 '14 at 07:11
  • 1
    @Maxim Not sure that's the case with most compilers. I've heard urban legends to that effect, but not seen any assembly for it. – chrylis -cautiouslyoptimistic- Mar 08 '14 at 07:11
  • @Maxim That is extremely unlikely in C++ for an `int`, given a reasonable compiler. The generated assembly code should be the same. – juanchopanza Mar 08 '14 at 07:13
  • 1
    @Maxim:with primitive types, the prefix and postfix arithmetic operations have identical performance. With objects, however, postfix operators can cause the object to create a copy of itself to preserve its initial state (to be returned as a result of the operation), as well as causing the side-effect of the operation. – Shiva Mar 08 '14 at 07:13

7 Answers7

3

In deference to the other answers posted, I feel you deserve to see an example of all three techniques in action. the following is highly situational, but none-the-less demonstrates what can happen:

The Code

#include <stdio.h>>

int i=1;

int main()
{
    printf("i=%d\n", i);

    printf("i++ : %d\n", i++);

    printf("++i : %d\n", ++i);

    i = i + 1;
    printf("i=i+1 : %d\n", i);

    return 0;
}

The Tools

Using clang 3.3 optimization set to -O2

The Assembly Listing

Cleaned and annotated for consumption:

; Basic printf()
movl    _i(%rip), %esi
leaq    L_.str(%rip), %rdi
xorb    %al, %al
callq   _printf

; post-increment (i++)
movl    _i(%rip), %esi
leal    1(%rsi), %eax
movl    %eax, _i(%rip)
leaq    L_.str1(%rip), %rdi
xorb    %al, %al
callq   _printf
leaq    L_.str2(%rip), %rdi

; pre-increment (++i)
movl    _i(%rip), %esi
incl    %esi
movl    %esi, _i(%rip)
xorb    %al, %al
callq   _printf
leaq    L_.str3(%rip), %rdi

; traditional (i = i + 1)
movl    _i(%rip), %esi
incl    %esi
movl    %esi, _i(%rip)
xorb    %al, %al
callq   _printf

The Difference

The stark difference is the storage of a temporary containing the prior value of i before increment in the case of i++ vs ++i. This is solely because said-temp is used as an argument to the printf() function invoke. Also note that in both the pre-increment and traditional mechanic, the resulting optimized assembly is identical (movl, incl, movl).

So does it make a difference if the post-increment operation is not evaluated ?

int main()
{
    i++;
    printf("i=%d\n", i);

    ++i;
    printf("i=%d\n", i);

    i = i + 1;
    printf("i=%d\n", i);

    return 0;
}

With the resulting assembling being:

; post-increment
movl    _i(%rip), %esi
incl    %esi
movl    %esi, _i(%rip)
leaq    L_.str(%rip), %rbx
movq    %rbx, %rdi
xorb    %al, %al
callq   _printf

; pre-increment
movl    _i(%rip), %esi
incl    %esi
movl    %esi, _i(%rip)
movq    %rbx, %rdi
xorb    %al, %al
callq   _printf

 ; traditional
movl    _i(%rip), %esi
incl    %esi
movl    %esi, _i(%rip)
movq    %rbx, %rdi
xorb    %al, %al
callq   _printf

Note that the rbx magic you see is unrelated and simply a way for caching the shared format string for printf(). In all three cases the identical code (movl,incl,movl) is used.

Conclusion

For a stand-alone statement, clang 3.3 will optimize all three to the same resulting code. If you introduce an evaluation dependance, post-increment and pre-increment can (and likely will) emit differing code. If your increment is a stand-alone statement, it makes no difference which you choose.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • Very good answer. That is really the only way to settle these kind of questions. I wonder what would happen in Java (not enough to try it out though :-) ) – juanchopanza Mar 08 '14 at 08:24
  • 1
    @juanchopanza egads I'm not ashamed to say I read asm far better than jbc, and i'm *marginal* at asm, so that tells you where my jbc is =P . This thing is *highly* situational, but I just wanted to point out the behavioral differences when used in different situations. glad you approve. – WhozCraig Mar 08 '14 at 08:26
2

Using prefix operators is faster than using postfix. i.e ++i is faster than i++.

For ++i, the value is increased and the new value is returned.

For i++, the value is increased, but the old value is returned. The performance difference comes as the older value needs to be stored first.

pizzaEatingGuy
  • 878
  • 3
  • 10
  • 19
  • It is like this for the postfix i.e. `i++` Original `i` is stored ++(*i); // call prefix operator original `i` is returned. – pizzaEatingGuy Mar 08 '14 at 07:31
1

Not sure about the first method since I have never incremented a counter that way (I am sure someone else will come in there) but for the second it would be better to use ++i than i++. The reasons have already been answered for that one in this question, but in a nutshell, i++ makes a copy of i whereas ++i works directly on the variable itself.

Community
  • 1
  • 1
Modred
  • 249
  • 3
  • 15
1

When you talk about increment or decrement , the first thing which come in mind is the operator used for increment or decrement i.e ++, --

In your first case of course that will do the increment job for you , but its indirect approach to increment techniques, and compiler will need to do two jobs, 1) Addition 2) Assignment.

In Second one the compiler Knows that it is increment operator , so it will increment that variable.

Adnan Ahmad Khan
  • 634
  • 2
  • 7
  • 25
1

++i is faster than other methods.

So your code will be :

int i = 0;
++i;
mherbert
  • 515
  • 3
  • 12
1

Here is some Java source code:

    int i = 0;

    i = i + 1;

    i += 1;

    ++i;

    i++;

And here is the corresponding Java byte code, obtained by javap -c:

 0: iconst_0      
 1: istore_1      

 2: iload_1       
 3: iconst_1      
 4: iadd          
 5: istore_1      

 6: iinc          1, 1

 9: iinc          1, 1

12: iinc          1, 1

As you can see, the last three syntactic forms compile to the same JVM instruction iinc. The first one generates more byte code, but I'd be surprised if the JIT compiler didn't optimize that difference away.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
0

@Modred: For the use of two methods that you quoted the result is not the same in the case of affectaion. for the following code the result isn't the same:

int i = 0, j = 0,k = 0;
cout << "i = " << i <<  " ,j = " << j << " ,k = " << k << '\n';
j = i++;
cout << "i = " << i <<  " ,j = " << j << " ,k = " << k << '\n';
k = ++i;
cout << "i = " << i <<  " ,j = " << j << " ,k = " << k << '\n';

OUTPUT

i = 0 ,j = 0 ,k = 0
i = 1 ,j = 0 ,k = 0
i = 2 ,j = 0 ,k = 2
  • When the pre-increment value is actually *used* for eval (such as the rhs of an assignment as you have here), then it becomes much less likely the temp will be elided. For the OP's specific stated condition, a stand-alone `j++;` vs `++j;` will result in identical asm from all but the most hideous of optimizers. Though I don't like relying on the optimizer for such things (its a crutch imho and makes for lazy engineering), they are in fact fundamentally different circumstances. – WhozCraig Mar 08 '14 at 07:30