-1

which is faster to find the even number if(n%2==0) or if(n&1==0) ?

def isEven(n):
    if n%2 == 0:
        return True
    return False
OR

def isEven(n):
    if n&1 == 1:
        return False
    return True
Beginner
  • 33
  • 4

2 Answers2

2

I would expect reasonable optimizing compilers for languages where those expressions are equivalent to implement both options equivalently.

In fact, I tried four different C++ compilers: gcc, clang, MSVC and icc and while every compiler implemented the idioms differently from the other compilers1, three out of four compilers implemented both idioms the same way.

Only icc generated different code, and in that case (n & 1) == 0 generated much better code than n % 2 == 0 - but you should consider that an icc bug.

However, not all languages implement optimizing compilers (ahead of time or JIT), and in particular interpreters may or may not optimize this similarly. If you are interested in a specific language or platform, you might consider tagging your question to reflect that.


1 That's actually surprising and unusual for such simple code. Overall clang generated the best code, followed by MSVC and then gcc. icc generated really terrible code for the n % 2 option. Weirdly, gcc generates strictly better code at -O1 than -O2.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • Its worth noting the the original code in the question is python, which is an interpreted language, so it probably won't apply as many optimizations as gcc, clang, and MSVC would for C. – Dillon Davis Jul 31 '18 at 05:20
  • 1
    @DillonDavis yes, I noted it - which is why I included the caveat about optimizing compilers (which was meant to include runtime-optimizing compilers, e.g., JITs). I'm not very familiar with the python interpreter, however. I know there are several options: it is safe to assume that something like CPython optimizes modules by a constant value? It would seem to be low hanging fruit. Because the question wasn't *tagged* python and didn't mention python, I had assumed a language agnostic answer (admittedly not covering all implementations) might be appropriate. – BeeOnRope Jul 31 '18 at 05:23
  • 1
    On second thought, perhaps the OP just failed to tag python. I added a section at the end of the answer kind of covering this, and UVed the other answer. – BeeOnRope Jul 31 '18 at 05:25
1

This looks like Python, so I tried it in Python(3.6):

from timeit import timeit
a = timeit(stmt='for i in range(100): i%2')
b = timeit(stmt='for i in range(100): i&1')
print(a, b)

Times vary somewhat wildly (thanks, garbage collector!) but in general this gets me around 4.7 seconds for i%2 and 6.3 seconds for i&1, which I would guess is probably not the answer you would expect.

I checked the bytecode using dis, and the only difference was the one line running BINARY_MODULO vs BINARY_AND, so I'm not sure why there's such a huge time discrepancy.

Turksarama
  • 1,136
  • 6
  • 13
  • The variance probably has more to do with constructing the range object and iteration than the garbage collector. Try repeating something like `5 & 1` and `5 % 2`, instead of repeating the whole for loop. – Dillon Davis Jul 31 '18 at 05:18
  • But the range iterator is created the same way for both, so It doesn't make any difference to the totals. To confirm that I ran it again with a `pass` statement in place of `i%2` and `i&`, and both round to 1.5 seconds. – Turksarama Jul 31 '18 at 05:21
  • I just tried using timeit from command line with `python -m timeit '5&1'` and `python -m timeit '5%2'` both of which averaged `0.0142 usec` per loop (best 3 of 100000000), twice. – Dillon Davis Jul 31 '18 at 05:25
  • I reversed the order and got exactly the same results, so I think the difference is likely to be in our interpreters rather than order of operations. Out of curiosity, what do you get if you use the range? – Turksarama Jul 31 '18 at 05:28
  • Python 3.5.2 produces `6.50781165715307 6.241488204104826` and Python 2.7.12 produces `4.794481992721558 4.476944923400879` – Dillon Davis Jul 31 '18 at 05:33
  • Interesting, I got similar results in Python 3.5. It looks like maybe there has been some optimization around the modulo operator in CPython3.6. – Turksarama Jul 31 '18 at 05:38