This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: floor division gives different result for int versus float.
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.2, Python 2.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: drj, eric.smith, mark.dickinson, tim.peters
Priority: low Keywords:

Created on 2009-06-30 10:55 by drj, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (6)
msg89915 - (view) Author: David Jones (drj) * Date: 2009-06-30 10:55
Consider: x//y != x//float(y) for some integer values of x and y.

For example, x = 2**54-1, and y = 2:

>>> x=2**54-1
>>> y=2
>>> x//y
9007199254740991L
>>> x//float(y)
9007199254740992.0
>>> _==x//y
False

I have no idea whether this should actually be a bug or not.  The 
behaviour (above) _is_ the documented behaviour (because the operands 
are documented as being converted to a common type).  But... I think 
there's a good case for computing the mathematically correct answer 
regardless of the types of the inputs.  For one thing, one of the 
reasons behind introducing the // operator was to make division the same 
regardless of whether the inputs were floating point or int.  Computing 
the mathematically correct answer (which since the answer is an integer 
is always exactly representable in Python) would be better, and simpler 
to document.
msg89916 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2009-06-30 11:08
Do you realize that 2**54-1 isn't exactly representable as a float?  It
requires 54 bits of precision, but the Python float format only has 53
bits available (on all popular boxes).

>>> 2**54-1
18014398509481983L
>>> float(_)  # rounds to closest representable float
18014398509481984.0

In fact, x//y == x//float(y) for only a small subset of integer x and y
values, mostly because only a small subset of integer x and y values are
exactly representable as floats (given that Python integers enjoy
unbounded precision, but floats only retain 53 bits).
msg89918 - (view) Author: David Jones (drj) * Date: 2009-06-30 11:53
I do realise that.  I still think the mathematically correct answer should 
be computed, since it can be.
msg89922 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-06-30 13:05
This is definitely a feature request rather than a bug.

As I understand it, you want to special-case floor division so that
if the argument types are (int, float) or (float, int) then the result is 
computed exactly.  Is that correct?  Note that the result of the floor 
division in your examples is a float, so it won't always be able to 
represent the result exactly anyway.  Or are you also proposing to change 
the return type to int/long?  What should (2**55-2)//2.0 return with your 
proposed change, and why?

Why single out floor division for this treatment?  What about the other 
binary operations?

I think this change adds complication to the language semantics without 
giving significant benefits.  It's true that there are a couple of places 
in Python that *do* special-case integers instead of converting to float 
(I'm thinking particularly of int <-> float comparisons, and math.log), 
but there are good reasons for those special cases and I don't think we 
should add to them.

Big -1 from me, I'm afraid.
msg89923 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2009-06-30 13:56
I agree with Mark: -1.

Do you have any specific use cases where this has caused problems, or is
this academic?

Maybe you can get some support for this on python-ideas, but I suggest
we close it in the meantime.
msg89924 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2009-06-30 14:16
Yup, -1 here too.  For dyadic arithmetic operations (+ - * / % //) on
mixed numeric types, Python's execution model coerces the operands to a
common type before computation begins.  Besides just being the way it's
worked "forever" in Python, it's consistent and explainable.  Growing a
wart for one case of one case would be inconsistent and deeply
surprising at a higher level.  Live with it ;-)
History
Date User Action Args
2022-04-11 14:56:50adminsetgithub: 50636
2009-06-30 14:26:11r.david.murraysetstatus: open -> closed
resolution: rejected
stage: resolved
2009-06-30 14:16:42tim.peterssetmessages: + msg89924
2009-06-30 13:56:32eric.smithsetmessages: + msg89923
2009-06-30 13:05:41mark.dickinsonsettype: behavior -> enhancement
messages: + msg89922
versions: + Python 2.7, Python 3.2, - Python 2.6
2009-06-30 12:44:29r.david.murraysetpriority: low
nosy: + mark.dickinson, eric.smith
2009-06-30 11:53:00drjsetmessages: + msg89918
2009-06-30 11:08:16tim.peterssetnosy: + tim.peters
messages: + msg89916
2009-06-30 10:55:40drjcreate