mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-68163: Correct conversion of Rational instances to float (GH-25619)
* gh-68163: Correct conversion of Rational instances to float Also document that numerator/denominator properties are instances of Integral. Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
This commit is contained in:
parent
9b9394df5f
commit
8464b754c4
4 changed files with 36 additions and 4 deletions
|
@ -58,11 +58,14 @@ The numeric tower
|
||||||
|
|
||||||
.. class:: Rational
|
.. class:: Rational
|
||||||
|
|
||||||
Subtypes :class:`Real` and adds
|
Subtypes :class:`Real` and adds :attr:`~Rational.numerator` and
|
||||||
:attr:`~Rational.numerator` and :attr:`~Rational.denominator` properties, which
|
:attr:`~Rational.denominator` properties. It also provides a default for
|
||||||
should be in lowest terms. With these, it provides a default for
|
|
||||||
:func:`float`.
|
:func:`float`.
|
||||||
|
|
||||||
|
The :attr:`~Rational.numerator` and :attr:`~Rational.denominator` values
|
||||||
|
should be instances of :class:`Integral` and should be in lowest terms with
|
||||||
|
:attr:`~Rational.denominator` positive.
|
||||||
|
|
||||||
.. attribute:: numerator
|
.. attribute:: numerator
|
||||||
|
|
||||||
Abstract.
|
Abstract.
|
||||||
|
|
|
@ -313,7 +313,7 @@ class Rational(Real):
|
||||||
so that ratios of huge integers convert without overflowing.
|
so that ratios of huge integers convert without overflowing.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.numerator / self.denominator
|
return int(self.numerator) / int(self.denominator)
|
||||||
|
|
||||||
|
|
||||||
class Integral(Rational):
|
class Integral(Rational):
|
||||||
|
|
|
@ -14,6 +14,27 @@ from fractions import Fraction as F
|
||||||
_PyHASH_MODULUS = sys.hash_info.modulus
|
_PyHASH_MODULUS = sys.hash_info.modulus
|
||||||
_PyHASH_INF = sys.hash_info.inf
|
_PyHASH_INF = sys.hash_info.inf
|
||||||
|
|
||||||
|
|
||||||
|
class DummyIntegral(int):
|
||||||
|
"""Dummy Integral class to test conversion of the Rational to float."""
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
return DummyIntegral(super().__mul__(other))
|
||||||
|
__rmul__ = __mul__
|
||||||
|
|
||||||
|
def __truediv__(self, other):
|
||||||
|
return NotImplemented
|
||||||
|
__rtruediv__ = __truediv__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def numerator(self):
|
||||||
|
return DummyIntegral(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def denominator(self):
|
||||||
|
return DummyIntegral(1)
|
||||||
|
|
||||||
|
|
||||||
class HashTest(unittest.TestCase):
|
class HashTest(unittest.TestCase):
|
||||||
def check_equal_hash(self, x, y):
|
def check_equal_hash(self, x, y):
|
||||||
# check both that x and y are equal and that their hashes are equal
|
# check both that x and y are equal and that their hashes are equal
|
||||||
|
@ -121,6 +142,13 @@ class HashTest(unittest.TestCase):
|
||||||
self.assertEqual(hash(F(7*_PyHASH_MODULUS, 1)), 0)
|
self.assertEqual(hash(F(7*_PyHASH_MODULUS, 1)), 0)
|
||||||
self.assertEqual(hash(F(-_PyHASH_MODULUS, 1)), 0)
|
self.assertEqual(hash(F(-_PyHASH_MODULUS, 1)), 0)
|
||||||
|
|
||||||
|
# The numbers ABC doesn't enforce that the "true" division
|
||||||
|
# of integers produces a float. This tests that the
|
||||||
|
# Rational.__float__() method has required type conversions.
|
||||||
|
x = F(DummyIntegral(1), DummyIntegral(2), _normalize=False)
|
||||||
|
self.assertRaises(TypeError, lambda: x.numerator/x.denominator)
|
||||||
|
self.assertEqual(float(x), 0.5)
|
||||||
|
|
||||||
def test_hash_normalization(self):
|
def test_hash_normalization(self):
|
||||||
# Test for a bug encountered while changing long_hash.
|
# Test for a bug encountered while changing long_hash.
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Correct conversion of :class:`numbers.Rational`'s to :class:`float`.
|
Loading…
Add table
Add a link
Reference in a new issue