mpf.__round__() returns mpf
Probably this will look non-intuitive, but underlying floating-point
arithmetic is binary, not decimal. Thus, round(x, n) sometimes will pick
up a decimal representation with more than n digits. This is something
common for CPython < 2.7 and < 3.1:
Python 2.6.6 (r266:84292, Aug 12 2014, 07:57:07)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> round(0.42754287856598971, 2)
0.42999999999999999
And with this patch as well:
Python 3.12.5+ (heads/3.12:0181aa2e3e, Aug 29 2024, 14:55:08) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mpmath import *
>>> round(mp.mpf(0.42754287856598971), 2)
mpf('0.42999999999999999')
>>> mp.pretty = True
>>> round(mp.mpf(0.42754287856598971), 2)
0.43
See also python/cpython#45921
Closes #455
This commit is contained in:
@@ -412,8 +412,13 @@ class _mpf(mpnumeric):
|
||||
def to_fixed(self, prec):
|
||||
return to_fixed(self._mpf_, prec)
|
||||
|
||||
def __round__(self, *args):
|
||||
return round(float(self), *args)
|
||||
def __round__(self, ndigits=0):
|
||||
ctx = self.context
|
||||
if ctx.isfinite(self):
|
||||
frac = MPQ(*self.as_integer_ratio())
|
||||
res = round(frac, ndigits)
|
||||
return ctx.convert(res)
|
||||
return self
|
||||
|
||||
|
||||
class _constant(_mpf):
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import decimal
|
||||
import math
|
||||
import operator
|
||||
import random
|
||||
|
||||
import pytest
|
||||
from hypothesis import example, given, settings
|
||||
from hypothesis import strategies as st
|
||||
|
||||
import mpmath
|
||||
from mpmath import (ceil, fadd, fdiv, floor, fmul, fneg, fp, frac, fsub, inf,
|
||||
isinf, isint, isnan, isnormal, iv, monitor, mp, mpc, mpf,
|
||||
mpi, nan, ninf, nint, nint_distance, pi, workprec)
|
||||
mpi, nan, ninf, nint, nint_distance, nstr, pi, workprec)
|
||||
from mpmath.libmp import (MPQ, finf, fnan, fninf, fnone, fone, from_float,
|
||||
from_int, from_pickable, from_str, mpf_add, mpf_mul,
|
||||
mpf_sub, round_down, round_nearest, round_up, to_int,
|
||||
@@ -607,3 +610,32 @@ def test_rand_precision():
|
||||
|
||||
def test_issue_260():
|
||||
assert mpc(str(mpc(1j))) == mpc(1j)
|
||||
|
||||
|
||||
@settings(max_examples=10000)
|
||||
@given(st.floats(allow_nan=True,
|
||||
allow_infinity=True,
|
||||
allow_subnormal=True),
|
||||
st.integers(min_value=0, max_value=15))
|
||||
@example(0.5, 0)
|
||||
@example(-0.5, 0)
|
||||
@example(1.5, 0)
|
||||
@example(-1.5, 0)
|
||||
@example(2.675, 2)
|
||||
@example(math.inf, 3)
|
||||
@example(-math.inf, 1)
|
||||
def test_round_bulk(x, n):
|
||||
mp.prec = fp.prec
|
||||
m = mpf(x)
|
||||
mr = round(m, n)
|
||||
xr = round(x, n)
|
||||
if isnan(x):
|
||||
assert isnan(mr)
|
||||
assert isnan(xr)
|
||||
else:
|
||||
assert float(mr) == xr
|
||||
# mp context doesn't support negative zero
|
||||
if not xr and math.copysign(1., xr) == -1.:
|
||||
return
|
||||
assert nstr(mr, n=14, base=16, strip_zeros=False,
|
||||
show_zero_exponent=True, binary_exp=True) == xr.hex()
|
||||
|
||||
Reference in New Issue
Block a user