Well, there are at least two low-level ways of determining whether a given number is even or not:
1. if (num%2 == 0) { /* even */ }
2. if ((num&1) == 0) { /* even */ }
I consider the second option to be far more elegant and meaningful, and that's the one I usually use. But it is not only a matter of taste; The actual performance may vary: usually the bitwise operations (such as the logial-and here) are far more efficient than a mod (or div) operation. Of course, you may argue that some compilers will be able to optimize it anyway, and I agree...but some won't.
Another point is that the second one might be a little harder to comprehend for less experienced programmers. On that I'd answer that it will probably only benefit everybody if these programmers take that short time to understand statements of this kind.
What do you think?
The given two snippets are correct only if num
is either an unsigned int, or a negative number with a two's complement representation. - As some comments righfuly state.
I define and use an "IsEven" function so I don't have to think about it, then I chose one method or the other and forget how I check if something is even.
Only nitpick/caveat is I'd just say that with the bitwise operation, you're assuming something about the representation of the numbers in binary, with modulo you are not. You are interpreting the number as a decimal value. This is pretty much guaranteed to work with integers. However consider that the modulo would work for a double, however the bitwise operation would not.
I don't think the modulo makes things more readable.
Both make sense, and both versions are correct. And computers store numbers in binary, so you can just use the binary version.The compiler may replace the modulo version with an efficient version. But that sounds like an excuse for prefering the modulo.
And readability in this very special case is the same for both versions. A reader that is new to programming may not even know that you can use modulo 2 to determine the even-ness of a number. The reader has to deduce it. He may not even know the modulo operator!
When deducing the meaning behind the statements, it could even be easier to read the binary version:
(I used the "b" suffix for clarification only, its not C/C++)
With the modulo version, you have to double-check how the operation is defined in its details (e.g. check documentation to make sure that
0 % 2
is what you expect).The binary
AND
is simpler and there are no ambiguities!Only the operator precedence may be a pitfall with binary operators. But it should not be a reason to avoid them (some day even new programmers will need them anyway).
It all depends on context. I actually prefer the &1 approach myself if it's a low level, system context. In many of these kinds of contexts, "is even" basically means has low bit zero to me, rather than is divisible by two.
HOWEVER: Your one liner has a bug.
You must go
not
The latter ANDs x with 1==0, ie it ANDs x with 0, yielding 0, which always evaluates as false of course.
So if you did it exactly as you suggest, all numbers are odd!
Any modern compiler will optimise away the modulo operation, so speed is not a concern.
I'd say using modulo would make things easier to understand, but creating an
is_even
function that uses thex & 1
method gives you the best of both worlds.You conclusion about performance is based on the popular false premise.
For some reason you insist on translating the language operations into their "obvious" machine counterparts and make the performance conclusions based on that translation. In this particular case you concluded that a bitwise-and
&
operation of C++ language must be implemented by a bitwise-and machine operation, while a modulo%
operation must somehow involve machine division, which is allegedly slower. Such approach is of very limited use, if any.Firstly, I can't imagine a real-life C++ compiler that would interpret the language operations in such a "literal" way, i.e. by mapping them into the "equivalent" machine operations. Mostly becuase more often than you think the equivalent machine operations simply do not exist.
When it comes to such basic operations with an immediate constant as an operand, any self-respecting compiler will always immediately "understand" that both
num & 1
andnum % 2
for integralnum
do exactly the same thing, which will make the compiler generate absolutely identical code for both expressions. Needless to add, the performance is going to be exactly the same.BTW, this is not called "optimization". Optimization, by definition, is when the compiler decides to deviate from the standard behavior of abstract C++ machine in order to generate the more efficient code (preserving the observable behavior of the program). There's no deviation in this case, meaning that there's no optimization.
Moreover, it is quite possible that on the given machine the most optimal way to implement both is neither bitwise-and nor division, but some other dedicated machine-specific instruction. On top of that, it is quite possible that there's won't be any need for any instruction at all, since even-ness/odd-ness of a specific value might be exposed "for free" through the processor status flags or something like that.
In other words, the efficiency argument is invalid.
Secondly, to return to the original question, the more preferable way to determine the even-ness/odd-ness of a value is certainly the
num % 2
approach, since it implements the required check literally ("by definition"), and clearly expresses the fact that the check is purely mathematical. I.e. it makes clear that we care about the property of a number, not about the property of its representation (as would be in case ofnum & 1
variant).The
num & 1
variant should be reserved for situations when you want access to the bits of value representation of a number. Using this code for even-ness/odd-ness check is a highly questionable practice.They're both pretty intuitive.
I'd give a slight edge to
num % 2 == 0
, but I really don't have a preference. Certainly as far as performance goes, it's probably a micro-optimization, so I wouldn't worry about it.