Skip to content

Add a note about formatting decimal.Decimal with the e/E symbol. #142019

@1nftf

Description

@1nftf
# Compare different precision on Decimal.
format(Decimal('0'), ".0E")      '0E+0'
format(Decimal('0'), ".1E")      '0.0E+1'
format(Decimal('0'), ".2E")      '0.00E+2'
format(Decimal('0'), ".3E")      '0.000E+3'
format(Decimal('0'), ".30E")     '0.000000000000000000000000000000E+30'
format(Decimal('-0.0'), ".0E")   '-0E-1'
format(Decimal('-0.0'), ".1E")   '-0.0E+0'
format(Decimal('-0.0'), ".2E")   '-0.00E+1'
format(Decimal('-0.0'), ".3E")   '-0.000E+2'
format(Decimal('-0.0'), ".30E")  '-0.000000000000000000000000000000E+29'

# Compare different 0 values.
format(0, ".3E")                '0.000E+00'
format(0.0, ".3E")              '0.000E+00'
format(-0.0, ".3E")             '-0.000E+00'
format(0j, ".3E")               '0.000E+00+0.000E+00j'
format(Decimal('0'), ".3E")     '0.000E+3'
format(Decimal('-0.0'), ".3E")  '-0.000E+2'

# Compare different format methods.
format(Decimal('0'), ".30E")                          '0.000000000000000000000000000000E+30'
format(1234512345123451234512345, ".30E")             '1.234512345123451205320704000000E+24'
format(Decimal('1234512345123451234512345'), ".30E")  '1.234512345123451234512345000000E+24'
"%.30E" % (Decimal('0'),)                             '0.000000000000000000000000000000E+00'  # exponent is 0, because the value is converted to float first
"%.30E" % (1234512345123451234512345,)                '1.234512345123451205320704000000E+24'
"%.30E" % (Decimal('1234512345123451234512345'),)     '1.234512345123451205320704000000E+24'

It seams that precision will affect exponent.

  • When formatting Decimal('0'), the exponent is equal to precision.
  • When formatting Decimal('-0.0'), the exponent is equal to precision-1.

In addition to the above behavior, the exponent is not padded to
two digits, which also makes it inconsistent with the built-in types.

Although the results are numerically correct, and the document
(https://docs.python.org/3/library/string.html#format-specification-mini-language)
does not limit the exponent when the coefficient is 0.
However, this can be confusing for users.

Maybe the document needs to add a note, or change the result of Decimal type
to be consistent with built-in types.

from decimal import Decimal

templates = (
    'format({v}, ".{p}E")',
    # 'f"{{{v}:.{p}E}}"',
    # '"{{:.{p}E}}".format({v})',
    # '"%.{p}E" % ({v},)',

    # 'format({v}, ".{p}e")'
    # 'f"{{{v}:.{p}e}}"',
    # '"{{:.{p}e}}".format({v})',
    # '"%.{p}e" % ({v},)',
)

values = (
    # 0,
    # 0.0,
    # -0.0,
    # complex(0),
    Decimal('0'),
    Decimal('-0.0'),

    # 0.001,
    # Decimal('0.001'),

    # 1,
    # 1.0,
    # Decimal('1'),

    # 10,
    # 10.0,
    # Decimal('10'),

    # 100,
    # 100.0,
    # Decimal('100'),

    # 1234512345123451234512345,
    # 1234512345123451234512345.0,
    # Decimal('1234512345123451234512345'),
)

precision = (
    0,
    1,
    2,
    3,
    # 4,
    # 5,
    # 6,
    # 7,
    # 8,
    # 9,
    # 10,
    30,
    # 100,
    # 1000,
    # 10000,
)

results = [
    ((expr := t.format(v=repr(v), p=p)), eval(expr))
    for t in templates
        for v in values
            for p in precision
]

max_len_expr = max(len(expr) for expr, val in results)
for expr, val in results:
    print(f"{expr}{' ' * ((max_len_expr)-len(expr))}  {repr(val)}")

Linked PRs

Metadata

Metadata

Assignees

Labels

docsDocumentation in the Doc dir

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions