Skip to content

Commit edb1ce9

Browse files
author
Release Manager
committed
gh-40279: Fix RealLiteral to float conversion Previously we see the following behavior sage: float(1.133759543500045e+153) 1.1337595435000451e+153 sage: float('1.133759543500045e+153') 1.133759543500045e+153 This is because `RealLiteral` constructor determine `prec=54`, so the string `1.133759543500045e+153` is first converted to 54 bits, then rounded to 53 bits. This introduces the error because of [double rounding](https://en.wikipedia.org/wiki/Rounding#Double_rounding). Also fix the issue where `n(RealNumber('12', base=16))` returns 12. (now it correctly returns 18.) ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> URL: #40279 Reported by: user202729 Reviewer(s): Martin Rubey, user202729
2 parents d953568 + 986a984 commit edb1ce9

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

src/sage/rings/real_mpfr.pyx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5694,28 +5694,29 @@ cdef class RealLiteral(RealNumber):
56945694
casting into higher precision rings.
56955695
"""
56965696

5697-
cdef readonly literal
5697+
cdef readonly str literal
56985698
cdef readonly int base
56995699

5700-
def __init__(self, RealField_class parent, x=0, int base=10):
5700+
def __init__(self, RealField_class parent, str x, int base=10):
57015701
"""
57025702
Initialize ``self``.
57035703
5704+
Note that the constructor parameters are first passed to :meth:`RealNumber.__cinit__`.
5705+
57045706
EXAMPLES::
57055707
57065708
sage: RealField(200)(float(1.3))
57075709
1.3000000000000000444089209850062616169452667236328125000000
5708-
sage: RealField(200)(1.3)
5710+
sage: RealField(200)(1.3) # implicit doctest
57095711
1.3000000000000000000000000000000000000000000000000000000000
57105712
sage: 1.3 + 1.2
57115713
2.50000000000000
57125714
sage: RR(1_0000.000000000000000000000000000000000000)
57135715
10000.0000000000
57145716
"""
57155717
RealNumber.__init__(self, parent, x, base)
5716-
if isinstance(x, str):
5717-
self.base = base
5718-
self.literal = x.replace('_', '')
5718+
self.base = base
5719+
self.literal = x.replace('_', '')
57195720

57205721
def __neg__(self):
57215722
"""
@@ -5728,10 +5729,25 @@ cdef class RealLiteral(RealNumber):
57285729
sage: RealField(300)(-(-1.2))
57295730
1.20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
57305731
"""
5731-
if self.literal is not None and self.literal[0] == '-':
5732+
if self.literal[0] == '-':
57325733
return RealLiteral(self._parent, self.literal[1:], self.base)
5733-
else:
5734-
return RealLiteral(self._parent, '-'+self.literal, self.base)
5734+
return RealLiteral(self._parent, '-' + self.literal, self.base)
5735+
5736+
def __float__(self):
5737+
"""
5738+
Return a Python float approximating ``self``.
5739+
This override is needed to avoid issues with rounding twice,
5740+
thus guaranteeing round-trip.
5741+
5742+
TESTS::
5743+
5744+
sage: float(1.133759543500045e+153)
5745+
1.133759543500045e+153
5746+
sage: for i in range(1000):
5747+
....: x = float(randint(1, 2**53) << randint(1, 200))
5748+
....: assert float(eval(preparse(str(x)))) == x, x
5749+
"""
5750+
return float(self.numerical_approx(53))
57355751

57365752
def numerical_approx(self, prec=None, digits=None, algorithm=None):
57375753
"""
@@ -5774,10 +5790,15 @@ cdef class RealLiteral(RealNumber):
57745790
<class 'sage.rings.real_mpfr.RealLiteral'>
57755791
sage: type(n(1.3))
57765792
<class 'sage.rings.real_mpfr.RealNumber'>
5793+
5794+
TESTS::
5795+
5796+
sage: n(RealNumber('12', base=16)) # abs tol 1e-14
5797+
18.0000000000000
57775798
"""
57785799
if prec is None:
57795800
prec = digits_to_bits(digits)
5780-
return RealField(prec)(self.literal)
5801+
return RealField(prec)(self.literal, self.base)
57815802

57825803

57835804
RR = RealField()

0 commit comments

Comments
 (0)