diff --git a/mathics/format/box/numberform.py b/mathics/format/box/numberform.py index fb56184b2..6e916e13d 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 0b66c9d0b..f711f1d23 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 f6bf8a2a9..bc9d094b6 100644 --- a/test/format/format_tests.yaml +++ b/test/format/format_tests.yaml @@ -171,17 +171,17 @@ -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" 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.