Mark Dickinson <[email protected]> added the comment:
> Mark, I tried `Fraction(10**23) // 1e22`, and I got 10.
Sorry: that result was with your PR (as it was at the time I wrote that
comment). On master, you do indeed get 10.
> I think the fact that floating-point rounding error sometimes causes
> strange results is not a reason to do really unexpected things like
> making 1.0 // 1/10 equal 9.0, if that can be reasonably avoided.
I understand, but I think in this case, the cure is worse than the disease. I
don't think converting the float to a Fraction in mixed-type operations is
going to work, for a number of reasons:
- it's changing the behaviour for _all_ the arithmetic operations, not just //
and %; that widens the scope for accidental breakage. For example, with the
latest commit 038664e6a6288f6113ab96103e57d3b25b39a8c2 on your PR:
>>> Fraction(1) + math.inf
inf
>>> math.inf + Fraction(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mdickinson/Python/cpython/Lib/fractions.py", line 391, in reverse
return float(fallback_operator(Fraction(a), b))
File "/Users/mdickinson/Python/cpython/Lib/fractions.py", line 130, in __new__
self._numerator, self._denominator = numerator.as_integer_ratio()
OverflowError: cannot convert Infinity to integer ratio
But on master, we have:
>>> import math
>>> from fractions import Fraction
>>> math.inf + Fraction(1)
inf
>>> Fraction(1) + math.inf
inf
- it's counter to the spirit of the numeric tower, where for most arithmetic
operations, values are propagated _up_ the tower (from Integral -> Rational ->
Real -> Complex) to the first common type before the operation is performed.
That keeps things simple; having some cases where values are converted down the
tower is going to cause confusion. (Comparisons are necessarily a special case:
the need to preserve transitivity of equality and trichotomy means that using
the same rules as for arithmetic operations won't fly)
- it introduces a non-obvious difference between mixed-mode Fraction-float and
int-float operations. For an int x and a float y, I'd expect the result of `x
<some_op> y` to be identical to the result of `Fraction(x) <some_op> y`.
So I'm sorry, but I do think having 1.0 // Fraction(1, 10) give 9.0 rather than
10.0 is the least worst option here. It's a surprise, but it's not a _new_
surprise: it's a surprise that's already there in the world of floating-point
arithmetic.
>>> 1.0 // 0.1
9.0
You're evaluating a discontinuous function _at_ a discontinuity, using a type
that's known for its inexactness. In that situation, getting the value for
_either_ side of that discontinuity is reasonable.
----------
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue32968>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com