5

Is there any benefit in performance using integer division operator over math.floor?

7 // 2

over

math.floor(7/2)
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
deChristo
  • 1,860
  • 2
  • 17
  • 29

2 Answers2

10

Integer division is much faster than a math.floor function call:

>>> import timeit
>>> timeit.timeit('7//2')
0.024671780910702337
>>> timeit.timeit('floor(7/2)', setup='from math import floor')
0.27053647879827736
>>> timeit.timeit('math.floor(7/2)', setup='import math')
0.3131167508719699

As you can see with this disassembly, using the math module's floor function (with import math and math.floor or from math import floor and floor) involve extra lookups and function calls over the plain integer division:

>>> import dis
>>> import math
>>> from math import floor
>>> def integer_division():
...     7//2
...
>>> def math_floor():
...     floor(7/2)
...
>>> def math_full_floor():
...     math.floor(7/2)
...
>>> dis.dis(integer_division)
  2           0 LOAD_CONST               3 (3)
              3 POP_TOP
              4 LOAD_CONST               0 (None)
              7 RETURN_VALUE
>>> dis.dis(math_floor)
  2           0 LOAD_GLOBAL              0 (floor)
              3 LOAD_CONST               3 (3.5)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE
>>> dis.dis(math_full_floor)
  2           0 LOAD_GLOBAL              0 (math)
              3 LOAD_ATTR                1 (floor)
              6 LOAD_CONST               3 (3.5)
              9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             12 POP_TOP
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
  • 1
    Your comparison isn't particularly meaningful, because as you can see the Python compiler has replaced any actual division logic by a precomputed constant. Consider using function arguments as dividend and divisor. Also, the disassembly doesn't tell anything about the runtimes of the VM commands. – Felix Dombek Sep 19 '19 at 15:23
1

Certainly, there's some overhead in a function call, and if you do this enough times, you see a difference in speed:

Run time for //: 12.940021991729736 sec
Run time for floor: 26.933987855911255 sec

Here's the code I ran:

from time import time
from math import floor

start_time = time()
for i in range(1, 10000):
    for j in range(1, 10000):
        result = i // j
print('Run time for //:', time() - start_time, 'sec')

start_time = time()
for i in range(1, 10000):
    for j in range(1, 10000):
        result = floor(i/j)
print('Run time for floor:', time() - start_time, 'sec')