Python Forum
Is // operator is the same as math.floor() - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Is // operator is the same as math.floor() (/thread-9009.html)



Is // operator is the same as math.floor() - quazirfan - Mar-17-2018

I am under the assumption 10 // 3 operation(Integer division) is the same as math.floor(10/3).

The results are the same for this simple arithmetic problem. But I am wording if they are interchangeable all the time.

Thank you.


RE: Is // operator is the same as math.floor() - wavic - Mar-17-2018

In [1]: import math

In [2]: for num in range(1, 1000000):
   ...:     if num // 3 == math.floor(num / 3):
   ...:         print('blah')
   ...:         

In [3]: 



RE: Is // operator is the same as math.floor() - DeaD_EyE - Mar-17-2018

The example is wrong. You are comparing num // 3 with floor(num).

deadeye@nexus ~ $ for num in range(10):
.................     num //=3
.................     floor = math.floor(num)
.................     if num == floor:
.................         print('Match', type(num), type(floor), num, floor)
.................         
Match <class 'int'> <class 'int'> 0 0
Match <class 'int'> <class 'int'> 0 0
Match <class 'int'> <class 'int'> 0 0
Match <class 'int'> <class 'int'> 1 1
Match <class 'int'> <class 'int'> 1 1
Match <class 'int'> <class 'int'> 1 1
Match <class 'int'> <class 'int'> 2 2
Match <class 'int'> <class 'int'> 2 2
Match <class 'int'> <class 'int'> 2 2
Match <class 'int'> <class 'int'> 3 3
This is xonsh, a mix of Python and shell.

If you use the integer division // and one of the operands is a float, the operation returns a float.
math.floor() returns always an integer.


RE: Is // operator is the same as math.floor() - wavic - Mar-17-2018

(Mar-17-2018, 02:28 PM)DeaD_EyE Wrote: The example is wrong. You are comparing num // 3 with floor(num).
Thanks! My mistake. Fixed in the code.


RE: Is // operator is the same as math.floor() - quazirfan - Mar-17-2018

(Mar-17-2018, 06:43 AM)wavic Wrote:
In [1]: import math

In [2]: for num in range(1, 1000000):
   ...:     if num // 3 == math.floor(num / 3):
   ...:         print('blah')
   ...:         

In [3]: 

I've wrote the following code,
import math

for i in range(0, 10000000):
    if i//3 != math.floor(i/3):
        print("Not equal")
And it never prints 'Not equal'. So I am guessing // and math.floor are interchangeable.

I also looked into The Python Standard Library - 10.3.1. Mapping Operators to Functions, and I've found the following line,
Division -- a // b -- floordiv(a, b)

Which confirms my assumption that these two are interchangeable.


RE: Is // operator is the same as math.floor() - casevh - Mar-17-2018

They are not interchangeable. There are some subtle differences.

The differences depend on the size and types of the values and the version of Python.

Internally, Python has two different concepts of division: floor division (floordiv) and true division (truediv). Floor division returns the quotient of the division. True division returns the "as accurate as possible" result.

The // operator is always floor division in all versions of Python. In Python 2, / can be either floor division or true division. It depends on the types of the arguments. In Python 3, / is always true division.

Here are some examples showing the differences.

Python 2

>>> from operator import floordiv, truediv
>>> from math import floor
>>> repr(floordiv(10,3)); repr(truediv(10,3)); repr(10//3); repr(10/3);floor(10/3)
'3'
'3.3333333333333335'
'3'
'3'
3.0
>>> repr(floordiv(10.0,3)); repr(truediv(10.0,3)); repr(10.0//3); repr(10.0/3);floor(10.0/3)
'3.0'
'3.3333333333333335'
'3.0'
'3.3333333333333335'
3.0
Python 3

>>> from operator import floordiv, truediv
>>> from math import floor
>>> repr(floordiv(10,3)); repr(truediv(10,3)); repr(10//3); repr(10/3);floor(10/3)
'3'
'3.3333333333333335'
'3'
'3.3333333333333335'
3
>>> repr(floordiv(10.0,3)); repr(truediv(10.0,3)); repr(10.0//3); repr(10.0/3);floor(10.0/3)
'3.0'
'3.3333333333333335'
'3.0'
'3.3333333333333335'
3
Here is an example where it is not true:

>>> floor(10**200/10**100) == 10**100
False
>>> 10**200//10**100 == 10**100
True
What is actually happening behind the scenes?

Let's define FLOOR as follows:
  • If the argument to FLOOR is an integer, it returns that integer unchanged.

  • If the argument to FLOOR is a float, then it returns a float equal to the mathematical floor of the argument.

Let's assume a and b are integers.

In Python 2, math.floor(a/b) is equivalent to FLOOR(float(floordiv(a,b))).
In Python 3, math.floor(a/b) is equivalent to int(FLOOR(truediv(a,b))).

In both versions, a/b is converted to float; either after the floordiv or during the truediv. Python 2 returns a float so you can recognize that the conversion has occurred. Python 3 always returns an integer. The result can give an artificial sense of accuracy. The conversion to float limit the accuracy of math.floor(a/b) to a maximum of 53 bits while a//b uses arbitrary precision integer arithmetic and is always 100% accurate.

Summary

If you are working with integers and want integer results for division, use // on both Python 2 and 3. And beware of implicit conversions to float in the math module.

casevh


RE: Is // operator is the same as math.floor() - quazirfan - Mar-18-2018

(Mar-17-2018, 11:40 PM)casevh Wrote: In Python 2, math.floor(a/b) is equivalent to FLOOR(float(floordiv(a,b))).

Why would it cast it to float? The precision is lost already when floordiv is used.


RE: Is // operator is the same as math.floor() - casevh - Mar-19-2018

(Mar-18-2018, 11:25 PM)quazirfan Wrote:
(Mar-17-2018, 11:40 PM)casevh Wrote: In Python 2, math.floor(a/b) is equivalent to FLOOR(float(floordiv(a,b))).

Why would it cast it to float? The precision is lost already when floordiv is used.

The following paragraph is true for Python 1 and 2.

The math module was originally written to provide access to the C math library. All arguments to functions in the C math must be converted to a supported floating point type. For Python, this is almost always a C double. The result of floordiv(int, int) remains an int so it must do the cast to float (technically a C double behind the scenes). The conversion from Python's arbitrary precision integers to C double is only reliable for values less than 2**53.

Here is an example for Python 2. Note that / and // and return the same result.

>>> 10**200/10**100
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000L
>>> 10**200//10**100
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000L
>>> math.floor(10**200/10**100)
1e+100
>>> int(math.floor(10**200/10**100))
10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104L
Python 3 is different since truediv is used and that already returns a float (aka C double). Then the C math library's floor function is called. And finally, the result is converted to an integer. But in Python 3, math.floor behaves differently if the argument is an integer.

Here is a Python 3 example.

>>> 10**200/10**100
1e+100
>>> math.floor(10**200/10**100)
10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104
>>> 10**200//10**100
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> math.floor(10**200//10**100)
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> 
Note the different results. In Python 3, the return types of math.floor, math.ceil, and math.trunc were changed to be an integer. The argument handling logic was also changed. If the argument is a type other than the native Python float, the functions will attempt to call the type's corresponding special methods: __floor__, __ceil__, or __trunc__.

If you are working with integer arguments, why would you want to use math.floor? // is faster for small values, always accurate and consistent, and behaves identically between Python 2 and Python 3.

$ py27 -m timeit -s "import math;a=10;b=3;f=math.floor" "f(a/b)"
10000000 loops, best of 3: 0.0444 usec per loop
$ py27 -m timeit -s "a=10;b=3" "a//b"
10000000 loops, best of 3: 0.0277 usec per loop
$ py27 -m timeit -s "from math import floor;a=10**200;b=10**100" "floor(a/b)"
1000000 loops, best of 3: 0.431 usec per loop
$ py27 -m timeit -s "a=10**200;b=10**100" "a//b"
1000000 loops, best of 3: 0.389 usec per loop
Note: the third example is faster with Python 3 and large numbers but then it is producing incorrect results.

casevh