From bad54feab66c5ddcc81b63d2054789d768e2f7e5 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 8 Jun 2025 18:27:16 +0300 Subject: [PATCH] Use context's rounding mode per default in the format() --- CHANGES | 4 ++-- mpmath/ctx_mp_python.py | 10 ++++++---- mpmath/libmp/libmpf.py | 15 +++++++-------- mpmath/tests/test_format.py | 10 ++++++++++ 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 2dedde74..39a278a9 100644 --- a/CHANGES +++ b/CHANGES @@ -33,8 +33,8 @@ Features: * Implement mpf.__format__(), see #819, #831, #850, #859, #857, #862, #881, #944 and #966 (Javier Garcia, Sergey B Kirpichev) * Support conversion from scalar ndarray's, see #821 (Sergey B Kirpichev) -* Support rounding modes in mpf.__format__, see #823, #831 and #834 (Javier - Garcia, Sergey B Kirpichev) +* Support rounding modes in mpf.__format__, see #823, #831, #834 + and #969 (Javier Garcia, Sergey B Kirpichev) * Support '%' presentation type for mpf, see #847 (Sergey B Kirpichev) * Support gmpy2-like rounding modes in to_str(), see #830 (Javier Garcia) * Implement 'a'/'A' formating types for mpf.__format__, see #841 and #870 diff --git a/mpmath/ctx_mp_python.py b/mpmath/ctx_mp_python.py index c661b7ea..d9e9f64f 100644 --- a/mpmath/ctx_mp_python.py +++ b/mpmath/ctx_mp_python.py @@ -396,6 +396,8 @@ class _mpf(mpnumeric): * ``'Z'``: rounding towards zero * ``'N'``: rounding to nearest (default) + If it's not specified, the context's rounding mode is used. + The rounding option must be set right before the presentation type: >>> x = mp.mpf('-1.2345678') @@ -428,9 +430,9 @@ class _mpf(mpnumeric): """ - _, _, (prec, _) = s._ctxdata + _, _, (prec, rounding) = s._ctxdata ctx = s.context - return format_mpf(s._mpf_, format_spec, prec, ctx._pretty_repr_dps) + return format_mpf(s._mpf_, format_spec, prec, rounding, ctx._pretty_repr_dps) def sqrt(s): return s.context.sqrt(s) @@ -701,9 +703,9 @@ class _mpc(mpnumeric): """ - _, _, (prec, _) = s._ctxdata + _, _, (prec, rounding) = s._ctxdata ctx = s.context - return format_mpc(s._mpc_, format_spec, prec, ctx._pretty_repr_dps) + return format_mpc(s._mpc_, format_spec, prec, rounding, ctx._pretty_repr_dps) complex_types = (complex, _mpc) diff --git a/mpmath/libmp/libmpf.py b/mpmath/libmp/libmpf.py index a65d9883..af61879e 100644 --- a/mpmath/libmp/libmpf.py +++ b/mpmath/libmp/libmpf.py @@ -1452,7 +1452,6 @@ def read_format_spec(format_spec): 'frac_separators': '', 'width': -1, 'precision': -1, - 'rounding': round_nearest, 'type': '' } @@ -1595,7 +1594,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, _pretty_repr_dps): +def format_digits(num, format_dict, prec, rnd, _pretty_repr_dps): capitalize = False if format_dict['type'] in list('AFGE'): capitalize = True @@ -1618,7 +1617,7 @@ def format_digits(num, format_dict, prec, _pretty_repr_dps): strip_last_zero = False strip_zeros = False - rnd = format_dict['rounding'] + rnd = format_dict.get('rounding', rnd) if not fmt_type or fmt_type == 'g': if not format_dict['alternate']: @@ -1729,9 +1728,9 @@ def format_digits(num, format_dict, prec, _pretty_repr_dps): return sign, int_part + digits -def format_mpf(num, format_spec, prec, _pretty_repr_dps): +def format_mpf(num, format_spec, prec, rnd, _pretty_repr_dps): format_dict = read_format_spec(format_spec) - sign, digits = format_digits(num, format_dict, prec, _pretty_repr_dps) + sign, digits = format_digits(num, format_dict, prec, rnd, _pretty_repr_dps) nchars = len(digits) + len(sign) lpad, rpad = calc_padding( nchars, format_dict['width'], format_dict['align']) @@ -1744,7 +1743,7 @@ def format_mpf(num, format_spec, prec, _pretty_repr_dps): + rpad*format_dict['fill_char'] -def format_mpc(num, format_spec, prec, _pretty_repr_dps): +def format_mpc(num, format_spec, prec, rnd, _pretty_repr_dps): format_dict = read_format_spec(format_spec) if format_dict['fill_char'] == '0': @@ -1760,10 +1759,10 @@ def format_mpc(num, format_spec, prec, _pretty_repr_dps): 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, _pretty_repr_dps) + sign_re, digits_re = format_digits(num[0], format_dict, prec, rnd, _pretty_repr_dps) fmt_sign = format_dict['sign'] format_dict['sign'] = '+' - sign_im, digits_im = format_digits(num[1], format_dict, prec, _pretty_repr_dps) + sign_im, digits_im = format_digits(num[1], format_dict, prec, rnd, _pretty_repr_dps) digits_im += 'j' if not fmt_type: diff --git a/mpmath/tests/test_format.py b/mpmath/tests/test_format.py index 22822d61..fc9ea02a 100644 --- a/mpmath/tests/test_format.py +++ b/mpmath/tests/test_format.py @@ -806,6 +806,16 @@ def test_mpf_fmt(): assert f"{mp.mpf('-0.1'):=.4Df}" == "-0.1000" +def test_default_rounding(): + x = mp.mpf(mp.pi) + + assert f"{x:.3f}" == '3.142' + mp.rounding = 'd' + assert f"{x:.3f}" == '3.141' + mp.rounding = 'u' + assert f"{x:.3f}" == '3.142' + + def test_issue_858(): for n in range(2, 15): str_num = '0.' + (n)*'9'