Fix repr to use _repr_digits also when pretty=True#927
Fix repr to use _repr_digits also when pretty=True#927skirpichev wants to merge 3 commits intompmath:masterfrom
_repr_digits also when pretty=True#927Conversation
|
This looks like a pretty big, breaking change. Pretty-printing until now intentionally suppressed a few digits so that in 99% of cases, all printed digits in the output will be correct, e.g. in doctests. With this change one will often have 2-3 wrong digits. Perhaps more importantly, until now setting |
That's why #921 still marked as "need decision" :-) And this is a draft. However, you can see that only doctests are affected. I.e. I doubt this will break something in sympy/diofant/etc.
My major concern is that in the current mpmath this breaks eval(repr) round-trip, in sense that you generally can't use pretty-printed output as input for mpf/mpc to recreate value: That affects all mpf's, not just computed by some algorithm (where - yes, we might expect that last digits will be just a noise). Maybe better is a CPython-like approach: using a shortest decimal representative as CPython does for IEEE doubles (I suspect it's possible for arbitrary precision as well). Other pros: better compatibility with fp backend. Cons: much more big compatibility break.
Hmm, can we generally represent an arbitrary mpf value with mp.prec precision in decimal with at most mp.dps decimal precision? It looks - from above example - this is not true. |
The difference between CPython and mpmath here is that for CPython the floats are always 53 bits and so the precision is known. With mpmath the precision is part of the information that is communicated to the user by the number of digits shown. |
That's true for gmpy2.mpfr/mpc as well. And for mpmath.
No, in mpmath you must specify precision either via context settings (like gmpy2) or via explicit >>> from mpmath import *
>>> am, bm = map(libmp.MPZ, [1111111111111111111111, 222222222222222222])
>>> a, b = (0, am, 0, am.bit_length()), (0, bm, 0, bm.bit_length())
>>> libmp.normalize(*a, 11, 'n')
(0, mpz(1927), 59, 11)
>>> libmp.normalize(*b, 11, 'n')
(0, mpz(1579), 47, 11)
>>> libmp.mpf_add(a, b, 11, 'n')
(0, mpz(241), 62, 8)
>>> libmp.normalize(*_, 11, 'n')
(0, mpz(241), 62, 8)
>>> libmp.mpf_add(libmp.normalize(*a, 11, 'n'), libmp.normalize(*b, 11, 'n'), 11, 'n')
(0, mpz(1927), 59, 11)Not too far from the MPFR. mpmath's floats just have no exponent limits, no signed zero c.f. IEEE floats. But you always know precision: >>> mpf(1).context
<mpmath.ctx_mp.MPContext object at 0x7f3b74fc4980>
>>> mpf(1).context.prec
53If you only look on the repr output (with |
ab7d627 to
b0a34e4
Compare
|
Ok, now this pass tests. I'll mark this ready for review. pr shouldn't be merged without approval from Fredrik or someone else (i.e. not me). With this patch, the mpmath repl with default settings behaves like pre-3.1 CPython repl (when float's are IEEE doubles): Currently used (when pretty-printing enabled) |
|
The main goal being to support the new repl mode, why not just use separate printing code (pretty-printing but with the repr precision) for this mode without breaking existing behavior? Maybe we could also have an extra parameter on the context object to make the repr precision explicit:
|
That was proposed in the issue thread as an option. Yet, I think it's only a half-way solution. You will have a similar problem in default Python repl, when Python 3.13.1 (tags/v3.13.1:0671451779, Dec 4 2024, 07:55:26) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mpmath import *
>>> 0.9402780567857644
0.9402780567857644
>>> mpf(str(_))
mpf('0.94027805678576437')
>>> v = _
>>> mp.pretty = True # (1)
>>> v
0.940278056785764
>>> mpf('0.940278056785764')
0.940278056785764
>>> _ == v
FalseAfter (1) you can't easily get a string representation of
Maybe. Though, either (1) it should be read-only or/and (2) with correct defaults (to print all required digits). |
|
Alternative: #933 |
closes #921