To check for odd and even integer, is the lowest bit checking more efficient than using the modulo?
>>> def isodd(num):
return num & 1 and True or False
>>> isodd(10)
False
>>> isodd(9)
True
To check for odd and even integer, is the lowest bit checking more efficient than using the modulo?
>>> def isodd(num):
return num & 1 and True or False
>>> isodd(10)
False
>>> isodd(9)
True
Yep. The timeit
module in the standard library is how you check on those things. E.g:
AmAir:stko aleax$ python -mtimeit -s'def isodd(x): x & 1' 'isodd(9)'
1000000 loops, best of 3: 0.446 usec per loop
AmAir:stko aleax$ python -mtimeit -s'def isodd(x): x & 1' 'isodd(10)'
1000000 loops, best of 3: 0.443 usec per loop
AmAir:stko aleax$ python -mtimeit -s'def isodd(x): x % 2' 'isodd(10)'
1000000 loops, best of 3: 0.453 usec per loop
AmAir:stko aleax$ python -mtimeit -s'def isodd(x): x % 2' 'isodd(9)'
1000000 loops, best of 3: 0.461 usec per loop
As you see, on my (first-day==old==slow;-) Macbook Air, the &
solution is repeatably between 7 and 18 nanoseconds faster than the %
solution.
timeit
not only tells you what's faster, but by how much (just run the tests a few times), which usually shows how supremely UNimportant it is (do you really care about 10 nanoseconds' difference, when the overhead of calling the function is around 400?!-)...
Convincing programmers that micro-optimizations are essentially irrelevant has proven to be an impossible task -- even though it's been 35 years (over which computers have gotten orders of magnitude faster!) since Knuth wrote
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
which as he explained is a quote from an even older statement from Hoare. I guess everybody's totally convinced that THEIR case falls in the remaining 3%!
So instead of endlessly repeating "it doesn't matter", we (Tim Peters in particular deserves the honors there) put in the standard Python library module timeit
, that makes it trivially easy to measure such micro-benchmarks and thereby lets at least some programmers convince themselves that, hmmm, this case DOES fall in the 97% group!-)
To be totally honest, I don't think it matters.
The first issue is readability. What makes more sense to other developers? I, personally, would expect a modulo when checking the evenness/oddness of a number. I would expect that most other developers would expect the same thing. By introducing a different, and unexpected, method, you might make code reading, and therefore maintenance, more difficult.
The second is just a fact that you probably won't ever have a bottleneck when doing either operation. I'm for optimization, but early optimization is the worst thing you can do in any language or environment. If, for some reason, determining if a number is even or odd is a bottleneck, then find the fastest way of solving the problem. However, this brings me back to my first point - the first time you write a routine, it should be written in the most readable way possible.
"return num & 1 and True or False" ? Wah! If you're speed-crazy (1) "return num & 1" (2) inline it: if somenumber % 2 == 1
is legible AND beats isodd(somenumber)
because it avoids the Python function call.
John brings up a good point. The real overhead is in the function call:
me@localhost ~> python -mtimeit -s'9 % 2'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'10 % 2'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'9 & 1'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'9 & 1'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x % 2' 'isodd(10)'
1000000 loops, best of 3: 0.334 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x % 2' 'isodd(9)'
1000000 loops, best of 3: 0.358 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x & 1' 'isodd(10)'
1000000 loops, best of 3: 0.317 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x & 1' 'isodd(9)'
1000000 loops, best of 3: 0.319 usec per loop
Interestingly both methods remore the same time without the function call.
The best optimization you can get is to not put the test into a function. 'number % 2
' and 'number & 1' are very common ways of checking odd/evenness, experienced programmers will recognize the pattern instantly, and you can always throw in a comment such as '# if number is odd, then blah blah blah' if you really need it to be obvious.
# state whether number is odd or even
if number & 1:
print "Your number is odd"
else:
print "Your number is even"
Apart from the evil optimization, it takes away the very idiomatic "var % 2 == 0" that every coder understands without looking twice. So this is violates pythons zen as well for very little gain.
Furthermore a = b and True or False has been superseded for better readability by
return True if num & 1 else False