Fix new-style formatting without type specifier (repr_dps vs dps)

Closes #943
This commit is contained in:
Sergey B Kirpichev
2025-04-23 07:04:24 +03:00
parent fcf6e9650c
commit 6c51c9d898
4 changed files with 25 additions and 10 deletions
+4 -1
View File
@@ -221,7 +221,10 @@ Setting the ``mp.pretty`` option will use the ``str()``-style output for ``repr(
>>> mpf(0.6)
mpf('0.59999999999999998')
To use enough digits to be able recreate value exactly, set ``mp.pretty_dps`` to ``"repr"``.
To use enough digits to be able recreate value exactly, set ``mp.pretty_dps``
to ``"repr"`` (default value is ``"str"``). Same option is used to control
default number of digits in the new-style string formatting *without format
specifier*, i.e. `format(exp(mpf(1)))`.
The number of digits with which numbers are printed by default is determined by
the working precision. To specify the number of digits to show without
+4 -2
View File
@@ -427,7 +427,8 @@ class _mpf(mpnumeric):
"""
_, _, (prec, _) = s._ctxdata
return format_mpf(s._mpf_, format_spec, prec)
ctx = s.context
return format_mpf(s._mpf_, format_spec, prec, ctx._pretty_repr_dps)
def sqrt(s):
return s.context.sqrt(s)
@@ -695,7 +696,8 @@ class _mpc(mpnumeric):
"""
_, _, (prec, _) = s._ctxdata
return format_mpc(s._mpc_, format_spec, prec)
ctx = s.context
return format_mpc(s._mpc_, format_spec, prec, ctx._pretty_repr_dps)
complex_types = (complex, _mpc)
+7 -7
View File
@@ -1601,7 +1601,7 @@ def fill_sep(digits, sep, prev, nmod, sep_range):
for pos in range(nmod, len(digits), sep_range))
def format_digits(num, format_dict, prec):
def format_digits(num, format_dict, prec, _pretty_repr_dps):
capitalize = False
if format_dict['type'] in list('AFGE'):
capitalize = True
@@ -1633,7 +1633,7 @@ def format_digits(num, format_dict, prec):
strip_last_zero = True
if precision < 0:
precision = repr_dps(prec)
precision = repr_dps(prec) if _pretty_repr_dps else prec_to_dps(prec)
if precision == 0:
precision = 1
@@ -1741,9 +1741,9 @@ def format_digits(num, format_dict, prec):
return sign, int_part + digits
def format_mpf(num, format_spec, prec):
def format_mpf(num, format_spec, prec, _pretty_repr_dps):
format_dict = read_format_spec(format_spec)
sign, digits = format_digits(num, format_dict, prec)
sign, digits = format_digits(num, format_dict, prec, _pretty_repr_dps)
nchars = len(digits) + len(sign)
lpad, rpad = calc_padding(
nchars, format_dict['width'], format_dict['align'])
@@ -1756,7 +1756,7 @@ def format_mpf(num, format_spec, prec):
+ rpad*format_dict['fill_char']
def format_mpc(num, format_spec, prec):
def format_mpc(num, format_spec, prec, _pretty_repr_dps):
format_dict = read_format_spec(format_spec)
if format_dict['fill_char'] == '0':
@@ -1772,10 +1772,10 @@ def format_mpc(num, format_spec, prec):
fmt_type = format_dict['type'].lower()
if not fmt_type:
format_dict['type'] = 'g'
sign_re, digits_re = format_digits(num[0], format_dict, prec)
sign_re, digits_re = format_digits(num[0], format_dict, prec, _pretty_repr_dps)
fmt_sign = format_dict['sign']
format_dict['sign'] = '+'
sign_im, digits_im = format_digits(num[1], format_dict, prec)
sign_im, digits_im = format_digits(num[1], format_dict, prec, _pretty_repr_dps)
digits_im += 'j'
if not fmt_type:
+10
View File
@@ -469,6 +469,10 @@ def test_mpf_fmt_cpython():
# No formatting code.
assert f'{mp.mpf(0.0):.0}' == '0e+00'
mp.pretty_dps = 'repr'
assert f'{mp.pi}' == '3.1415926535897931'
mp.pretty_dps = 'str'
assert f'{mp.pi}' == '3.14159265358979'
@settings(max_examples=20000)
@@ -489,10 +493,12 @@ def test_mpf_floats_bulk(fmt, x):
the same results for default precision.
'''
mp.pretty_dps = "repr"
if not x and math.copysign(1, x) == -1:
return # skip negative zero
spec = read_format_spec(fmt)
if spec['frac_separators'] and vinfo < (3, 14):
mp.pretty_dps = "str"
return # see also python/cpython#130860
if not spec['type'] and spec['precision'] < 0 and math.isfinite(x):
# The mpmath could choose a different decimal
@@ -503,6 +509,7 @@ def test_mpf_floats_bulk(fmt, x):
if spec['type'] == '%' and math.isinf(100*x):
return # mpf can't overflow
assert format(x, fmt) == format(mp.mpf(x), fmt)
mp.pretty_dps = "str"
@settings(max_examples=20000)
@@ -511,8 +518,10 @@ def test_mpf_floats_bulk(fmt, x):
allow_infinity=True,
allow_subnormal=True))
def test_mpc_complexes(fmt, z):
mp.pretty_dps = "repr"
if ((not z.real and math.copysign(1, z.real) == -1)
or (not z.imag and math.copysign(1, z.imag) == -1)):
mp.pretty_dps = "str"
return # skip negative zero
spec = read_format_spec(fmt)
if spec['frac_separators'] and vinfo < (3, 14):
@@ -527,6 +536,7 @@ def test_mpc_complexes(fmt, z):
assert complex(format(z)) == complex(format(mp.mpc(z)))
else:
assert format(z, fmt) == format(mp.mpc(z), fmt)
mp.pretty_dps = "str"
def test_mpc_fmt():