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()) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 4d8dafa0515..f9fd378d4bf 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -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 """ diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 10ff6b8baae..421859afdfc 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)] + [-4, -4, -2, -2, 0, 0, 2, 2, 4, 4, 6] + + 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): 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)