2

For example, say I want to find all numbers between 1 and 1000 that are divisible by 3 and 5. Would the code:

for i in range(1,1000):
    if i % 3==0 and i %5 == 0:
        blah

be less efficient than say

for i in range(1,1000):
    if i%3==0:
       if i%5==0:
           blah

Does the computer check for BOTH conditions? For example, if i=10. Would the computer in the first one compute BOTH i%3 and i%5, or would it compute i%3 and then break? In that case, it would be more efficient to put the easy to check/reject condition to the left, correct?

3 Answers3

3

In python and many languages there is short circuit evaluation of the boolean expressions. This means the evaluation stops as soon as are we sure about the truth value of the boolean expression. In this regard, both your code fragments are equivalent.

You could however optimise by changing the order. For example it's better to use:

if i % 5 == 0 and i % 3 == 0

The reason is that it's rarer for a number to be a multiple of 5 and so this expression will fail earlier for most of the cases.

For example, if we check for the numbers from 1 to 150, the check i % 5 == 0 will fail for 120 numbers. So we are going to perform 120 checks for i % 5 == 0 and 30 checks for i % 5 == 0 and i % 3 == 0. This is a total of 180 checks. Similarly, for if i % 3 == 0 and i % 5 == 0 we are going to perform 100 + 2 * 50 = 200 checks.

JuniorCompressor
  • 19,631
  • 4
  • 30
  • 57
  • That's what I thought, it always better to quickly reject things. Thanks! –  May 01 '15 at 16:07
2

No, it will return false as soon as one of the conditions is false. This is called short-circuiting. See python docs.

James Elderfield
  • 2,389
  • 1
  • 34
  • 39
  • Oh, that was simple. Is it the same in every language? –  May 01 '15 at 16:04
  • 1
    I'm not sure about "every" language but here is a list of some that [do support it](http://en.wikipedia.org/wiki/Short-circuit_evaluation) – James Elderfield May 01 '15 at 16:06
  • 1
    @avid19 some languages require different syntax - for example in VB.NET the base `And` and `Or` don't short-circuit but `AndAlso` and `OrElse` do. – jonrsharpe May 01 '15 at 16:09
-1

Along side the other answers that explains the short-circuiting, The both do one job and there is no much difference between the performance.

See the following benchmark :

s1="""
for i in range(1,1000):
    if i % 3==0 and i %5 == 0:
        pass
"""
s2="""
for i in range(1,1000):
    if i%3==0:
       if i%5==0:
           pass

    """


print ' first: ' ,timeit(stmt=s1, number=1000)
print 'second : ',timeit(stmt=s2, number=1000) 

Result :

 first:  0.0738339424133
second :  0.0790829658508

as you can see the difference is 0.006 and its because of an extra block loading in the second part.

Also you can use dis module for disassembling the python bytecode :

first loop using and :

 21           0 SETUP_LOOP              58 (to 61)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1)
              9 LOAD_CONST               2 (1000)
             12 CALL_FUNCTION            2
             15 GET_ITER            
        >>   16 FOR_ITER                41 (to 60)
             19 STORE_FAST               0 (i)

 22          22 LOAD_FAST                0 (i)
             25 LOAD_CONST               3 (3)
             28 BINARY_MODULO       
             29 LOAD_CONST               4 (0)
             32 COMPARE_OP               2 (==)
             35 POP_JUMP_IF_FALSE       16
             38 LOAD_FAST                0 (i)
             41 LOAD_CONST               5 (5)
             44 BINARY_MODULO       
             45 LOAD_CONST               4 (0)
             48 COMPARE_OP               2 (==)
             51 POP_JUMP_IF_FALSE       16

 23          54 JUMP_ABSOLUTE           16
             57 JUMP_ABSOLUTE           16
        >>   60 POP_BLOCK           
        >>   61 LOAD_CONST               0 (None)
             64 RETURN_VALUE 

and for second :

26           0 SETUP_LOOP              61 (to 64)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1)
              9 LOAD_CONST               2 (1000)
             12 CALL_FUNCTION            2
             15 GET_ITER            
        >>   16 FOR_ITER                44 (to 63)
             19 STORE_FAST               0 (i)

 27          22 LOAD_FAST                0 (i)
             25 LOAD_CONST               3 (3)
             28 BINARY_MODULO       
             29 LOAD_CONST               4 (0)
             32 COMPARE_OP               2 (==)
             35 POP_JUMP_IF_FALSE       16

 28          38 LOAD_FAST                0 (i)
             41 LOAD_CONST               5 (5)
             44 BINARY_MODULO       
             45 LOAD_CONST               4 (0)
             48 COMPARE_OP               2 (==)
             51 POP_JUMP_IF_FALSE       60

 29          54 JUMP_ABSOLUTE           60
             57 JUMP_ABSOLUTE           16
        >>   60 JUMP_ABSOLUTE           16
        >>   63 POP_BLOCK           
        >>   64 LOAD_CONST               0 (None)
             67 RETURN_VALUE  
Mazdak
  • 105,000
  • 18
  • 159
  • 188
  • -1, the assembly for these two expressions is *identical*. Any difference in timing is a result of the variance and unreliability of the test environment. – Nick Bastin May 01 '15 at 16:11
  • 1
    @NickBastin I think was showing that, they said "there is no(t) much difference between the performance". –  May 01 '15 at 16:13
  • @NickBastin As avid19 says i didn't say there is no any difference! check out the edit! – Mazdak May 01 '15 at 16:24