1

Which test is faster : equality or inequality ?

For example, in a big while loop, should the condition be a>0 rather than a!=0 ?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Ealhad
  • 1,912
  • 20
  • 27
  • You could try timing it. – zondo Mar 26 '16 at 15:35
  • 3
    There is no defined performance difference between these constructs. Thus, even *if* any difference exists in practice, it's not guaranteed to persist across platforms, interpreter versions, etc. – Charles Duffy Mar 26 '16 at 15:35
  • Moreover, which of these is faster will vary **greatly** on the data type in question; if it's a class that implements `__eq__` or such, then there you are. Without locking down data type, interpreter version, CPU, and numerous other variables, there simply *is* no canonical answer for this question. – Charles Duffy Mar 26 '16 at 15:36
  • 2
    There is a good chance that whatever you do within that while loop, takes considerably longer than the comparison made by the while loop at each iteration.. – Dyrborg Mar 26 '16 at 15:38
  • 5
    ...so, if you want to be Pythonic, use the code that's easiest for the reader to follow, and don't worry about speed. In general, `a > 0` is the safer approach, since that way you can't get into an endless loop if the value is somehow negative. – Charles Duffy Mar 26 '16 at 15:38
  • @CharlesDuffy I suspected that. Thanks ! – Ealhad Mar 26 '16 at 15:52
  • Thank you for the tags edit @MartijnPieters, I don't know SO as well as you do. – Ealhad Mar 26 '16 at 16:11

5 Answers5

8

When asking yourself a question about speed differences between different operators, use the timeit module to measure. They are equally fast:

>>> import timeit
>>> timeit.timeit('a > 0', 'a = 1', number=10**7)
0.2486400604248047
>>> timeit.timeit('a > 0', 'a = 0', number=10**7)
0.2411360740661621
>>> timeit.timeit('a != 0', 'a = 1', number=10**7)
0.24765801429748535
>>> timeit.timeit('a != 0', 'a = 0', number=10**7)
0.24990510940551758

That's the comparisons repeated 10 million times, and if you re-run the above tests you'll find the timings can vary somewhat and none are clear winners.

You should be focusing on readability here, not speed. A simple integer comparison is going to be an infinitesimal part of your overall execution speed, even in a loop.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
5

If we’re talking about a being an int, then on my machine at this very moment, an equality check is very slightly faster than a greater-than check. You can quickly check that yourself using the timeit module:

>>> for s in 'a = 2', 'a = 0', 'a = -2':
        timeit('a != 0', s)
        timeit('a > 0', s)

0.06030992519848155
0.06666935212976455
0.053299842422489974
0.06516424110179742
0.05866621696540619
0.06685335186756447

However, those numbers are super close to another. So you should only take one thing out of this answer: It does not matter.

These kind of things are micro optimizations. And micro optimizations very rarely have any impact on the real performance of an application. It is a lot more likely that there are thousand other parts in your application that have more impact on the performance to make this difference negligible. You should only care about such things if you actually profiled your application and confirmed that this part of your code is a bottleneck that is taking down the performance of your application. But for this particular code, I doubt that will ever be the case.

So please, don’t bother about these minor difference but just use whatever makes more sense: Considering that these two checks have a different semantic meaning (a number being unequal to zero, or a number being larger than zero), choose the one that you actually meant to check for.

poke
  • 369,085
  • 72
  • 557
  • 602
1

For me, timeit doesn't show any consistently noticeable difference (assuming you're working with integers)...

>>> timeit.timeit('1 > 0')
0.031796932220458984
>>> timeit.timeit('1 != 0')
0.03249096870422363
>>> timeit.timeit('1 > 0')
0.03250718116760254
>>> timeit.timeit('1 != 0')
0.031616926193237305

As stated in the comments on this question, rather than focusing on what operator is the fastest, you should focus on the one that makes the most sense. If you really mean "do this while a is greater than 0" than use >. The amount of time spent doing this comparison is going to be a very minor contributor to your overall runtime, so it probably isn't worth worrying which operator is faster...

mgilson
  • 300,191
  • 65
  • 633
  • 696
0

Is it the bottleneck of your program? Only if the answer is yes, you should be worried about it. Moreover, there is not something that says this will be sure faster in any OS, or with any type.


For fun, I timed the while loop:

#!/usr/bin/python
import time

a = 1000000
t0 = time.time()
while(a != 0):
    a = a - 1
t1 = time.time()

total = t1-t0
print total

and:

a > 0 gives:

0.12652015686

a != 0 gives:

0.111998081207


For timing, check this: How can I time a code segment for testing performance with Pythons timeit?


But, use timeit, as Martijn Pieters suggested (Get time of execution of a block of code in Python 2.7), like this:

#!/usr/bin/python

import timeit
a = 1000000
start_time = timeit.default_timer()
while(a != 0):
    a = a - 1
elapsed = timeit.default_timer() - start_time
print elapsed

which gave for a > 0:

0.10852098465

and for a != 0:

0.108459949493

See the difference in the two timing approaches!

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 2
    Always use the [`timeit` module](https://docs.python.org/2/library/timeit.html) for comparisons. It'll disable garbage collection and use the most accurate timer available for your platform. You should also focus on *just* the operator, really. – Martijn Pieters Mar 26 '16 at 15:43
  • @MartijnPieters, thanks ninja, new to Python here! Weird that the answers in my linked question do not highlight it. Should I delete the answer or modify it? – gsamaras Mar 26 '16 at 15:45
  • I'm indeed surprised no-one actually used `timeit` in that post. I've left a comment on the accepted answer; they could more easily have used `timeit.timeit(function, number=n)` there and get more accurate results still. – Martijn Pieters Mar 26 '16 at 15:50
  • It's up to you if you want to keep your answer here. – Martijn Pieters Mar 26 '16 at 15:51
  • @MartijnPieters, that's remarkable, you made me learn something new today, hurray! :D Thanks, I updated my answer. – gsamaras Mar 26 '16 at 15:56
  • 1
    For what it's worth, I've added a `timeit` answer to the question you found. That's rather terrible, that there was no answer to that effect there. – Martijn Pieters Mar 26 '16 at 16:03
  • I wanted that to happen @MartijnPieters, but of course I couldn't ask for it (maybe when I learn more I can do that on my own)! Thanks again, cheers! – gsamaras Mar 26 '16 at 16:05
0

I think this somewhat leaden test program shows in the case of character and integer compares there is basically no difference

import string
def numericgtmostfail():
    for i in range(100):
        x= i > 99
    return x

def numericgtmostsucceed():
    for i in range(100):
        x= i > 1
    return x

def numericnemostsucceed():
    for i in range(100):
        x= i != 99
    return x

def numericnemostfail():
    for i in range(100):
        x= i != i
    return x

def chgtmostfail():
    for s in (string.lowercase * 4)[0:100]:
        x = s > 'y'
    return x

def chgtmostsucceed():
    for s in (string.lowercase * 4)[0:100]:
        x = s > 'a'
    return x

def chnemostfail():
    for s in (string.lowercase * 4)[0:100]:
        x = s != s 
    return x

def chnemostsucceed():
    for s in (string.lowercase * 4)[0:100]:
        x = s != 'a' 
    return x

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("numericgtmostfail()", setup="from __main__ import numericgtmostfail"))
    print(timeit.timeit("numericgtmostsucceed()", setup="from __main__ import numericgtmostsucceed"))
    print(timeit.timeit("numericnemostsucceed()", setup="from __main__ import numericnemostsucceed"))
    print(timeit.timeit("numericnemostfail()", setup="from __main__ import numericnemostfail"))
    print(timeit.timeit("chgtmostfail()", setup="from __main__ import chgtmostfail"))
    print(timeit.timeit("chgtmostsucceed()", setup="from __main__ import chgtmostsucceed"))
    print(timeit.timeit("chnemostsucceed()", setup="from __main__ import chnemostsucceed"))
    print(timeit.timeit("chnemostfail()", setup="from __main__ import chnemostfail"))
Vorsprung
  • 32,923
  • 5
  • 39
  • 63