1

I saw someone use this method to increment a variable:

r = (r + 1) & 0xf;

Is that method better/faster than just using:

r++;

Why would someone use a bitwise and, with 0xf, if it just duplicates?

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
Anthony
  • 41
  • 1
  • 1
  • 4

8 Answers8

14

Those are not the same. The first one increments r then performs a modulo operation on it, effectively doing the same thing as:

r = (r + 1) % 16;
James McNellis
  • 348,265
  • 75
  • 913
  • 977
11

The expression:

r = (r + 1) & 0xf;

Is actually equivalent to this (assuming r is guaranteed to be non-negative):

r = (r + 1) % 16;

Because of this, it's impossible to compare either of the statements above with r++. It doesn't matter which is "faster" or "better" because they don't do the same thing in the first place.

greyfade
  • 24,948
  • 7
  • 64
  • 80
4

As others have stated, the two code snippets you posted are not equivalent. Updating the question based on that information the question becomes,

   Is r = (r + 1) & 0xf; better than r = (r + 1) % 16;?

Though one may come up with a situation in which the former notation is more applicable, I would say that in general no, it is not. The modulo operator makes it much clearer what is happening, and I imagine that most compilers will perform this optimization for you. Do not unnecessarily sacrifice readability for speed. (Of course, if you want to be sure about any possible speed difference, just compile both snippets to assembler, e.g. with gcc -S, and compare the output.)

Edit: nobar's remark below shows that things are usually not as straightforward as they appear. Unlike &, % is an arithmetic operator, and it is as such bound to some addtional rules (e.g. to ensure that negative arguments are properly handled). The two statements above are only equivalent for non-negative values or r. To ensure that the compiler can make such an assumption about r, it is best to declare it unsigned.

Community
  • 1
  • 1
Stephan202
  • 59,965
  • 13
  • 127
  • 133
  • 1
    Your examples of modulus and bit-masking are not perfectly equivalent. They can yield different results if r is a negative number. As a result of this, the compiler will not be able to optimize the modulus operation down to the mask operation unless it knows that the input value is non-negative after the addition. The best way to ensure this is to declare r to be an unsigned value. By the way, your suggestion to review the assembler was a good one (although it's not for beginners). – Brent Bradburn Nov 01 '09 at 09:53
3

Those lines aren't equivalent. The first one will go back to zero if r is 15 before the call.

Cogwheel
  • 22,781
  • 4
  • 49
  • 67
2

r++ should never be used to increment unless you need the pre-incremented value as an rvalue. Most compilers will optimize it to ++r if the post-increment functionality isn't needed, but its best not to rely on it. But you probably meant to ask for a comparison between ++r and (r + 1) & 0xf;, then I would submit that any fractional improvement that the latter might have one some particular compiler or hardware is insignificant compared to the greater difficulty in understanding and maintaining the code.

In general, avoid trying to be overly clever in optimizations that might not apply to another architecture.

Jherico
  • 28,584
  • 8
  • 61
  • 87
  • The two expressions are completely unrelated, one is not an optimization of the other. And using `++r` over `r++` only makes a difference for objects that are expensive to copy. Certainly not the case for numbers, so your "should never be used" rule is an exaggeration. – Idelic Oct 31 '09 at 20:57
  • 1
    idelic: the difference between ++r and r++ can be significant even for simple objects, if the compiler does not optimize and the operation is repeated a number of times. – dar7yl Oct 31 '09 at 21:32
  • 1
    Hmm, so the entire language is named after an operation that should generally be avoided. I think there is some significance there ;^) – Jeremy Friesner Oct 31 '09 at 22:05
  • I didn't say it should be avoided. I said it shouldn't be used if you don't need the pre-incremented value as an rvalue. Really not that complicated. And idelic, saying the difference is only important for objects with expensive copies, well that's really not true. a) its sloppy coding and b) even a *fast* copy constructor will seem pretty slow if its in some multiply nested loop. STL container iterators are particularly vulnerable to this kind of problem. – Jherico Oct 31 '09 at 23:29
  • 3
    Yes, surely the whole point of C++ is its backwards compatibility with C. `++C` would make the original value (C) unavailable, so C++ is the correct name. – alex tingle Nov 01 '09 at 00:31
  • @dar7yl: Your hypothetical compiler would be utter garbage. Please name a seriously used compiler where there is a significant performance penalty for using r++ instead of ++r for an int variable. – Idelic Nov 01 '09 at 04:45
  • @Jherico: Obviously, an STL container iterator for anything other than a vector would qualify as "expensive to copy". Primitive numeric types, for example, qualify as "cheap to copy", and using prefix increment for them is perfectly correct, not "sloppy." – Idelic Nov 01 '09 at 04:51
  • ...using *postfix* increment for them is perfectly correct, of course. – Idelic Nov 01 '09 at 04:52
  • Idelic: Your argument basically boils down 'I don't need to care about which increment I use because the compiler will fix it for me', which to me is the very definition of sloppy. Especially since the compiler will *only* fix it for non-object types. Asshats using post-increment without regard to performance or the type of the variable have at times been the bane of my existence because looping on STL containers can be pervasive in a codebase – Jherico Nov 01 '09 at 07:40
  • Also, dar7yl said specifically 'simple objects' which does not include primitive types like int. The whole problem is that because an object's post-increment function might have side effect, so compilers cannot reliably optimize them out – Jherico Nov 01 '09 at 07:42
  • If you want to keep arguing your case, take it here: http://stackoverflow.com/questions/24901/ which basically says the same thing, don't use i++ over ++i unless you have a *specific reason* for doing so. – Jherico Nov 01 '09 at 07:48
1

There's no equivalence in the two code examples you give.
1) Is a fast way of limiting the value from 0 to 15 and doing a wrap-around to zero once the value exceeds 15.
2) Just increments a value with no upper limit ( apart from the inherent limit imposed by the size of the type that r is declared with i.e it would wrap > 255 if r were declared as unsigned char etc )

1) is an equivalent to doing this

if (r + 1 > 15 )
{
   r = 0;
}

So it may be more optimal on certain types of hardware because it eliminates the need for a branch etc

zebrabox
  • 5,694
  • 1
  • 28
  • 32
1

Comparing
r=(r+1) & 0xf;
and
++r;
r %= 0x10;

With any kind of compiler optimization when r is an integer they should be the same.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Zanson
  • 3,991
  • 25
  • 31
0

Perhaps you should ask yourself which method is clear and easy to understand for a programmer maintaining your code... C and C++ give a lot of syntax to say the same things and compilers are smarter than programmers in most situations, so the responsibility is to make code easy to understand.

JPCF
  • 2,232
  • 5
  • 28
  • 50