views:

392

answers:

8

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?

+14  A: 

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
+3  A: 

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

Cogwheel - Matthew Orlando
+11  A: 

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
+1. r can be 0, too :)
sellibitze
Bah. Pedant. :)
greyfade
+1  A: 

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
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
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
Hmm, so the entire language is named after an operation that should generally be avoided. I think there is some significance there ;^)
Jeremy Friesner
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
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
@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
@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
...using *postfix* increment for them is perfectly correct, of course.
Idelic
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
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
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
+4  A: 
Stephan202
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).
nobar
@nobar: good point! I'll update the answer.
Stephan202
+1  A: 

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
+1  A: 

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.

Zanson
@ Dave Hinton, Zansom: Sorry for the double rollback; I totally failed at reading the diff in the edit history...
James McNellis
A: 

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