Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in python why if rank: is faster than if rank != 0:

When I changed

for i in range(0, 100):
    rank = ranks[i]
    if rank != 0:
        pass

to:

for i in range(0, 100):
    rank = ranks[i]
    if rank:
        pass

I found the second code is much more efficient, why?

bench mark it, and in my situation ranks is an numpy array of integer. The difference is much more.

import numpy as np
import time
N = 1000000
ranks = np.random.random_integers(0, 10, N)
start = time.time()
for i in range(0, N):
    rank = ranks[i]
    if rank != 0:
        pass

print time.time() - start
start = time.time()
for i in range(0, N):
    rank = ranks[i]
    if rank:
        pass
print time.time() - start
start = time.time()
for i in range(0, N):
    if i != 0:
        pass

print time.time() - start
start = time.time()
for i in range(0, N):
    if i:
        pass
print time.time() - start

output:

1.15917396545
0.45020198822
0.123136997223
0.122531175613
like image 920
BerSerK Avatar asked Aug 05 '13 02:08

BerSerK


1 Answers

Distilling the checks to the core

for i in range(0,100):
  if i != 0:
    pass

and

for i in range(0,100):
  if i:
    pass

We see there is a difference

$ python -m timeit 'for i in range(0,100):' ' if i != 0:' '  pass'
100000 loops, best of 3: 4.69 usec per loop
$ python -m timeit 'for i in range(0,100):' ' if i:' '  pass'
100000 loops, best of 3: 4.18 usec per loop

The difference is that while the first case involves comparing to zero, the second case just tests if false.

To see what it is doing, use dis:

>>> def f():
...  for i in range(0,100):
...    if i:
...      pass
...
>>> def g():
...  for i in range(0,100):
...    if i != 0:
...      pass
...
>>> from dis import dis
>>> dis(f)
  2           0 SETUP_LOOP              32 (to 35)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (0)
              9 LOAD_CONST               2 (100)
             12 CALL_FUNCTION            2
             15 GET_ITER
        >>   16 FOR_ITER                15 (to 34)
             19 STORE_FAST               0 (i)

  3          22 LOAD_FAST                0 (i)
             25 POP_JUMP_IF_FALSE       16

  4          28 JUMP_ABSOLUTE           16
             31 JUMP_ABSOLUTE           16
        >>   34 POP_BLOCK
        >>   35 LOAD_CONST               0 (None)
             38 RETURN_VALUE
>>> dis(g)
  2           0 SETUP_LOOP              38 (to 41)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (0)
              9 LOAD_CONST               2 (100)
             12 CALL_FUNCTION            2
             15 GET_ITER
        >>   16 FOR_ITER                21 (to 40)
             19 STORE_FAST               0 (i)

  3          22 LOAD_FAST                0 (i)
             25 LOAD_CONST               1 (0)   <-- this only happens in != 0
             28 COMPARE_OP               3 (!=)  <-- this only happens in != 0
             31 POP_JUMP_IF_FALSE       16

  4          34 JUMP_ABSOLUTE           16
             37 JUMP_ABSOLUTE           16
        >>   40 POP_BLOCK
        >>   41 LOAD_CONST               0 (None)
             44 RETURN_VALUE
like image 117
SheetJS Avatar answered Oct 05 '22 16:10

SheetJS