From 60c701158fd8436a6a126a223de6d99d7e5b5412 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 21 Oct 2026 11:24:07 +0000 Subject: [PATCH 1/2] MATH-260 InputForm of a low-precision number shows the digits it keeps, as in WMA Since #2060 a PrecisionReal with fewer than 64 bits of precision keeps its value with 64 bits (``_extended``), but InputForm and FullForm printed only the digits that the precision gives, so the printed form did not read back as the same number. As in WMA, InputForm and FullForm now print the shortest decimal string that reads back as the kept value; OutputForm and StandardForm still print the digits of the precision. WMA 15: InputForm[3.1415926535897932385`3] -> 3.1415926535897932385`3. InputForm[-4.326563712`2] -> -4.326563712`2. InputForm[-4.32`4] -> -4.32`4. (the last two are in test/format/format_tests-WMA.yaml; the Mathics expectation for -4.326563712`2 in format_tests.yaml is updated to match). Co-Authored-By: Claude Opus 5.5 --- mathics/format/box/numberform.py | 33 ++++++++++++++++++--- test/builtin/atomic/test_numbers.py | 46 +++++++++++++++++++++++++++++ test/format/format_tests.yaml | 2 +- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/mathics/format/box/numberform.py b/mathics/format/box/numberform.py index fb56184b2d..6e916e13d3 100644 --- a/mathics/format/box/numberform.py +++ b/mathics/format/box/numberform.py @@ -168,8 +168,24 @@ def int_to_string_shorter_repr( return value_str +def _stored_digits(extended: sympy.Float) -> tuple[str, int]: + """ + The shortest decimal string that reads back as ``extended``, and its + number of significant digits. As in WMA, InputForm shows these for a + number of low precision: 3.1415926535897932385`3. + """ + bits = extended._prec + with mpmath.workprec(bits): + value = extended._to_mpmath(bits) + for n in range(1, dps(bits) + 4): + s = mpmath.nstr(value, n) + if sympy.Float(s, precision=bits)._mpf_ == extended._mpf_: + break + return s, n + + def real_to_tuple_info( - real: Real, digits: Optional[int] + real: Real, digits: Optional[int], stored: bool = False ) -> tuple[str, int, bool, int, int]: """ Convert ``real`` to a tuple representing that value. The tuple consists of: @@ -180,7 +196,9 @@ def real_to_tuple_info( * Updated value of digits, according to the number precision. * the decimal precision. - If ``digits`` is None, we use the default precision. + If ``digits`` is None, we use the default precision. If ``stored`` is + True, a PrecisionReal that keeps more bits than its precision shows + all the digits it keeps. """ binary_precision = real.precision if isinstance(real, PrecisionReal): @@ -202,7 +220,10 @@ def real_to_tuple_info( is_nonnegative = True return s, exponent, is_nonnegative, digits, precision - if digits is None: + if stored and isinstance(real, PrecisionReal) and real._extended is not None: + s, digits = _stored_digits(real._extended) + value = real._extended + elif digits is None: if real.is_machine_precision: value = real.value s = repr(value) @@ -462,7 +483,11 @@ def numberform_to_boxes( if digits_after_decimal_point is None: is_int = True elif isinstance(value, Real): - s, exp, is_nonnegative, digits, precision = real_to_tuple_info(value, digits) + # As in WMA, InputForm and FullForm show all the digits kept. + stored = digits is None and form in ("System`InputForm", "System`FullForm") + s, exp, is_nonnegative, digits, precision = real_to_tuple_info( + value, digits, stored + ) else: raise ValueError("Expected Real or Integer.") diff --git a/test/builtin/atomic/test_numbers.py b/test/builtin/atomic/test_numbers.py index 0b66c9d0b3..f711f1d239 100644 --- a/test/builtin/atomic/test_numbers.py +++ b/test/builtin/atomic/test_numbers.py @@ -1070,6 +1070,52 @@ def test_low_precision_storage(str_expr, str_expected, msg): check_evaluation(str_expr, str_expected, failure_message=msg) +@pytest.mark.parametrize( + ("str_expr", "str_expected", "msg"), + [ + ( + "ToString[3.1415926535897932385`3, InputForm]", + '"3.1415926535897932385`3."', + "InputForm shows the digits that are kept, not the precision", + ), + ( + "ToString[FullForm[3.1415926535897932385`3]]", + '"3.1415926535897932385`3."', + None, + ), + ( + "ToString[-3.1415926535897932385`3, InputForm]", + '"-3.1415926535897932385`3."', + None, + ), + ("ToString[3.1415926535897932385`3]", '"3.14"', "OutputForm: the precision"), + ( + "StringTake[ToString[N[Pi, 20] + 0``3, InputForm], 22]", + '"3.1415926535897932385`"', + None, + ), + ( + "Precision[1.5`20 - ToExpression[ToString[1.4`2, InputForm]]]", + "0.853872", + "reading InputForm back gives the same kept value", + ), + ( + "ToExpression[ToString[#, InputForm]] === # &[N[1/3, 3]]", + "True", + None, + ), + ( + "Precision[1.5`20 - ToExpression[ToString[N[1/3, 3], InputForm]]]", + "Precision[1.5`20 - N[1/3, 3]]", + None, + ), + ], +) +def test_low_precision_input_form(str_expr, str_expected, msg): + """Compared with WMA 15""" + check_evaluation(str_expr, str_expected, failure_message=msg) + + @pytest.mark.parametrize( ("str_expr", "str_expected", "msg"), [ diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml index f6bf8a2a97..830862e137 100644 --- a/test/format/format_tests.yaml +++ b/test/format/format_tests.yaml @@ -181,7 +181,7 @@ System`StandardForm: "\n -\n 4.33\n" System`TraditionalForm: "\n -\n 4.33\n" text: - System`InputForm: -4.33`2. + System`InputForm: -4.326563712`2. System`OutputForm: '-4.3' System`StandardForm: -4.33`2. System`TraditionalForm: -4.33`2. From 51e9ef5cf871e1d1c22ae1d61fa2ad1871c34152 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 21 Oct 2026 11:28:26 +0000 Subject: [PATCH 2/2] MATH-260 format tests: LaTeX and MathML InputForm of -4.326563712`2 show the kept digits These forms go through InputForm too, so they now show the digits that the number keeps, as the text form does; WMA's MathML InputForm also shows -4.326563712 (test/format/format_tests-WMA.yaml). Co-Authored-By: Claude Opus 5.5 --- test/format/format_tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml index 830862e137..bc9d094b6e 100644 --- a/test/format/format_tests.yaml +++ b/test/format/format_tests.yaml @@ -171,12 +171,12 @@ -4.326563712`2: msg: A negative Real number latex: - System`InputForm: '-4.33' + System`InputForm: '-4.326563712' System`OutputForm: '\text{-4.3}' System`StandardForm: '-4.33' System`TraditionalForm: '-4.33' mathml: - System`InputForm: -4.33 + System`InputForm: -4.326563712 System`OutputForm: -4.3 System`StandardForm: "\n -\n 4.33\n" System`TraditionalForm: "\n -\n 4.33\n"