classification
Title: Decimal.__str__ has no way to force exact decimal representation
Type: enhancement Stage: resolved
Components: Versions: Python 3.10
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: facundobatista, mark.dickinson, rhettinger, sim1234, steven.daprano
Priority: normal Keywords:

Created on 2021-02-24 10:59 by sim1234, last changed 2021-03-02 18:43 by mark.dickinson. This issue is now closed.

Messages (7)
msg387618 - (view) Author: Szymon (sim1234) Date: 2021-02-24 10:59
str(Decimal("0.00000001")) always returns "1E-8" and there is no way to directly get the "0.00000001" string back without writting custom method for converting DecimalTuple to string. This is caused by arbitrary choice of `and leftdigits > -6` condition in https://github.com/python/cpython/blob/master/Lib/_pydecimal.py#L1052 .
The hardcoded value of -6 should be parametrizable. This can be done by adding it as argument to the __str__ method or maybe by adding it to the decimal context.
msg387621 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-02-24 12:03
This is by design: the choice of -6 is not arbitrary, but follows the standard that the Decimal class is based on. Quoting from http://speleotrove.com/decimal/daconvs.html#reftostr:

> If the exponent is less than or equal to zero and the adjusted exponent is greater than or equal to -6, [...]

"str" isn't parameterizable (at least, not without a major change to the way that Python works), so if you're using it you have to accept the compromises it makes. If you want finer control over the string representation of Decimal objects, use Python's formatting capabilities:

    >>> from decimal import Decimal
    >>> x = Decimal("1e-8")
    >>> format(x, 'f')
    '0.00000001'
msg387625 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2021-02-24 15:10
Python 3.5 to 3.9 are all in feature freeze and can accept no new features; new features can only be added to 3.10.

But having said that, I agree with Mark that the correct solution here is to use format, not str. Szymon, unless you have a very argument against format, I think this should be closed.
msg387626 - (view) Author: Szymon (sim1234) Date: 2021-02-24 15:58
Thanks for the replies. The use of format works great. Maybe it's worth mentioning in the documentation because using "%f" % Decimal("0.00000001") leds to loosing precision (cast to float64 I guess) while using f"{"Decimal('0.00000001'):f}" does the thing correctly.
msg387724 - (view) Author: Szymon (sim1234) Date: 2021-02-26 13:30
One more thing: It's worth mentioning that by default, you'll get only 28 significant digits of precision, so doing f"{Decimal('1234567890123456789012.12345678').normalize():f}" will produce '1234567890123456789012.123457' (two last digits got rounded).
msg387727 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-02-26 14:40
Sure, but that has nothing to do with string representations or formatting, so I don't see how it's relevant for this issue: the rounding happens when you call `normalize`.
msg387951 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-03-02 18:43
Closing here; the built-in formatting should be sufficient, as discussed.
History
Date User Action Args
2021-03-02 18:43:45mark.dickinsonsetstatus: open -> closed
resolution: rejected
messages: + msg387951

stage: resolved
2021-02-26 14:40:56mark.dickinsonsetmessages: + msg387727
2021-02-26 13:30:28sim1234setmessages: + msg387724
2021-02-24 15:58:21sim1234setmessages: + msg387626
2021-02-24 15:10:10steven.dapranosetnosy: + steven.daprano

messages: + msg387625
versions: - Python 3.6, Python 3.7, Python 3.8, Python 3.9
2021-02-24 12:03:57mark.dickinsonsetmessages: + msg387621
2021-02-24 11:49:07xtreaksetnosy: + rhettinger, facundobatista, mark.dickinson
2021-02-24 10:59:48sim1234create