Python Forum
Is // operator is the same as math.floor()
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Is // operator is the same as math.floor()
#1
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.
Reply
#2
In [1]: import math

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

In [3]: 
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#3
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.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#4
(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.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#5
(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.
Reply
#6
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
Reply
#7
(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.
Reply
#8
(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
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Get numpy ceil and floor value for nearest two decimals klllmmm 4 1,264 Jun-07-2023, 07:35 AM
Last Post: paul18fr
  Floor approximation problem in algorithm gradlon93 3 945 Dec-14-2022, 07:48 PM
Last Post: Gribouillis
  math.log versus math.log10 stevendaprano 10 2,388 May-23-2022, 08:59 PM
Last Post: jefsummers
  Floor division problem with plotting x-axis tick labels Mark17 5 2,090 Apr-03-2022, 01:48 PM
Last Post: Mark17
  Why getting ValueError : Math domain error in trig. function, math.asin() ? jahuja73 3 3,764 Feb-24-2021, 05:09 PM
Last Post: bowlofred
Photo Locate Noise floor level for a spectral data in Python Ranjan_Pal 1 3,044 Dec-19-2020, 10:04 AM
Last Post: Larz60+
  Floor division return value Chirumer 8 3,760 Nov-26-2020, 02:34 PM
Last Post: DeaD_EyE
  mapping-camera-coordinates-to-a-2d-floor-plan fauveboyxuuki 0 2,531 Dec-10-2019, 10:34 PM
Last Post: fauveboyxuuki
  Floor Division cf. math.floor() Devarishi 3 2,218 May-22-2019, 06:35 AM
Last Post: heiner55
  Logic of using floor division and modulus for a different variable at different time SB_J 2 2,500 Nov-01-2018, 07:25 PM
Last Post: SB_J

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020