Is & faster than % when checking for odd numbers?

29,058

Solution 1

Yep. The timeit module in the standard library is how you check on those things. E.g:

$ python -m timeit -s 'def isodd(x): x & 1' 'isodd(9)'
1000000 loops, best of 3: 0.446 usec per loop
$ python -m timeit -s 'def isodd(x): x & 1' 'isodd(10)'
1000000 loops, best of 3: 0.443 usec per loop
$ python -m timeit -s 'def isodd(x): x % 2' 'isodd(9)'
1000000 loops, best of 3: 0.461 usec per loop
$ python -m timeit -s 'def isodd(x): x % 2' 'isodd(10)'
1000000 loops, best of 3: 0.453 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!-)

Solution 2

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.

Solution 3

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"

Solution 4

"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.

Solution 5

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.

Share:
29,058
riza
Author by

riza

.

Updated on September 02, 2021

Comments

  • riza
    riza over 2 years

    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