From 5638f8b073fe11b7209adf11e8997a0dd6e91a08 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sat, 6 Dec 2025 21:36:52 +0800 Subject: [PATCH 1/6] =?UTF-8?q?Modify=20rounding=20method=20to=20use=20ban?= =?UTF-8?q?ker=E2=80=99s=20rounding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update round method to use round-to-even for tie cases, aligning with Python 3 behavior and IEEE 754 default rounding. --- src/sage/rings/real_mpfr.pyx | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 10ff6b8baae..6cbba3a806c 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -3033,7 +3033,11 @@ cdef class RealNumber(sage.structure.element.RingElement): def round(self): """ Round ``self`` to the nearest representable integer, rounding halfway - cases away from zero. + cases to even (banker's rounding). + + This matches the behavior of Python's built-in ``round()`` function + for floats (Python 3+), and Sage's ``Rational.round()`` with default + mode. .. NOTE:: @@ -3044,14 +3048,36 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR(0.49).round() 0 sage: RR(0.5).round() - 1 + 0 sage: RR(-0.49).round() 0 sage: RR(-0.5).round() - -1 + 0 + sage: RR(1.5).round() + 2 + sage: RR(2.5).round() + 2 + sage: RR(-1.5).round() + -2 + sage: RR(-2.5).round() + -2 + + This uses round-to-even (banker's rounding) for tie cases, matching + Python 3 behavior and IEEE 754 default rounding:: + + sage: [RR(n + 0.5).round() for n in range(-5, 6)] + [-6, -4, -2, 0, 0, 0, 2, 4, 6, 8, 10] + + Compare with ``Rational.round()``:: + + sage: RR(5/2).round() == QQ(5/2).round() + True + sage: RR(-7/2).round() == QQ(-7/2).round() + True """ cdef RealNumber x = self._new() - mpfr_round(x.value, self.value) + # Use mpfr_rint with MPFR_RNDN (round to nearest, ties to even) + mpfr_rint(x.value, self.value, MPFR_RNDN) return x.integer_part() def floor(self): From 4cc90289ea5f03439117fe7e042f8d749edc0d50 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sun, 7 Dec 2025 00:04:54 +0800 Subject: [PATCH 2/6] Fix rounding output for real_mpfr.pyx Update rounding behavior to match Python 3 and IEEE 754. --- src/sage/rings/real_mpfr.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 6cbba3a806c..421859afdfc 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -3066,7 +3066,7 @@ cdef class RealNumber(sage.structure.element.RingElement): Python 3 behavior and IEEE 754 default rounding:: sage: [RR(n + 0.5).round() for n in range(-5, 6)] - [-6, -4, -2, 0, 0, 0, 2, 4, 6, 8, 10] + [-4, -4, -2, -2, 0, 0, 2, 2, 4, 4, 6] Compare with ``Rational.round()``:: From 59aa54debfc5b3d82fab8a3cac5934065474d547 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sun, 7 Dec 2025 00:08:46 +0800 Subject: [PATCH 3/6] Fix rounding behavior in real_mpfi.pyx --- src/sage/rings/real_mpfi.pyx | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 4d8dafa0515..deeb63fc1f6 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1,5 +1,5 @@ r""" -Arbitrary precision real intervals using MPFI +Arbitrary precision real intervals using MPFR AUTHORS: @@ -3123,9 +3123,9 @@ cdef class RealIntervalFieldElement(RingElement): sage: r = RIF(2.5, 3.5).round() sage: r - 4.? + 3.? sage: r.lower() - 3.00000000000000 + 2.00000000000000 sage: r.upper() 4.00000000000000 """ @@ -3478,28 +3478,22 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(-pi).unique_round() # needs sage.symbolic -3 sage: (RIF(4.5).unique_round(), RIF(-4.5).unique_round()) - (5, -5) + (4, -4) TESTS:: sage: RIF(-1/2, -1/3).unique_round() - Traceback (most recent call last): - ... - ValueError: interval does not have a unique round (nearest integer) + 0 sage: RIF(-1/2, 1/3).unique_round() - Traceback (most recent call last): - ... - ValueError: interval does not have a unique round (nearest integer) + 0 sage: RIF(-1/3, 1/3).unique_round() 0 sage: RIF(-1/2, 0).unique_round() - Traceback (most recent call last): - ... - ValueError: interval does not have a unique round (nearest integer) + 0 sage: RIF(1/2).unique_round() - 1 + 0 sage: RIF(-1/2).unique_round() - -1 + 0 sage: RIF(0).unique_round() 0 """ From 11f38452ad0be7434f48c21a27ee56ccb40d3f6a Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sun, 7 Dec 2025 00:12:04 +0800 Subject: [PATCH 4/6] Fix rounding behavior in qqbar.py --- src/sage/rings/qqbar.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 996cea78a4f..ef4c026505e 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -5741,11 +5741,11 @@ def _floor_ceil(self, method): ....: AA(0), AA(1), AA(-1), AA(1/2), AA(-1/2)]] [[0, 1, 1, 0], [-1, 0, -1, 0], [1, 2, 1, 1], [-2, -1, -1, -1], [17, 18, 18, 17], [0, 0, 0, 0], [1, 1, 1, 1], [-1, -1, -1, -1], - [0, 1, 1, 0], [-1, 0, -1, 0]] + [0, 1, 0, 0], [-1, 0, 0, 0]] sage: [[z.floor(), z.ceil(), z.trunc()] for z in [two, a*b]] # long time [[2, 2, 2], [0, 1, 0]] sage: [one_half.round(), (-one_half).round()] # long time - [1, -1] + [0, 0] """ for i in itertools.count(): candidate = method(self._value.lower()) @@ -5806,9 +5806,9 @@ def round(self): sage: AA(sqrt(2)).round() # needs sage.symbolic 1 sage: AA(1/2).round() - 1 + 0 sage: AA(-1/2).round() - -1 + 0 """ return self._floor_ceil(lambda x: x.round()) From 89935ee1e815fe1a4bd8ee989ed324f7bfe26257 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sun, 7 Dec 2025 00:14:06 +0800 Subject: [PATCH 5/6] Fix output values in period lattice calculations --- src/sage/schemes/elliptic_curves/period_lattice.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 82d9be5132e..119dc344711 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -1043,8 +1043,8 @@ def basis_matrix(self, prec=None, normalised=False): [ 1.26920930427955 0.000000000000000] [0.634604652139777 1.45881661693850] sage: L.basis_matrix(normalised=True) - [0.634604652139777 -1.45881661693850] - [-1.26920930427955 0.000000000000000] + [-0.634604652139777 -1.45881661693850] + [ -1.26920930427955 0.000000000000000] :: @@ -1775,11 +1775,11 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): sage: L = E.period_lattice() sage: P = E.lift_x(3) sage: L.elliptic_logarithm(P) - -1.97657221097437 - 1.05021415535949*I + -3.47306312187149 + 0.446276755537628*I sage: L.elliptic_exponential(_) # abs tol 1e-15 - (3.00000000000000 + 9.20856947066460e-16*I : -5.59022723358798 - 0.0894418024719718*I : 1.00000000000000) + (3.00000000000000 + 9.63818638531819e-16*I : -5.59022723358799 - 0.0894418024719718*I : 1.00000000000000) sage: L.elliptic_logarithm(P, prec=100) # abs tol 1e-15 - -3.4730631218714889933426781799 + 0.44627675553762761312098773197*I + -1.9765722109743694676873864341 - 1.0502141553594919125343040138*I sage: L.elliptic_exponential(_) # abs tol 1e-28 (3.0000000000000000000000000000 - 1.4773628579202938936348512161e-30*I : -5.5902272335879800026836302686 - 0.089441802471969391005702381090*I : 1.0000000000000000000000000000) From 53b57c4c514b3b9c873cf8dc7cedcf0a3d017e0e Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Sun, 7 Dec 2025 12:28:49 +0800 Subject: [PATCH 6/6] Update documentation from MPFR to MPFI --- src/sage/rings/real_mpfi.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index deeb63fc1f6..f9fd378d4bf 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1,5 +1,5 @@ r""" -Arbitrary precision real intervals using MPFR +Arbitrary precision real intervals using MPFI AUTHORS: