Skip to content

GH-105774: Clarify operation of normalize() #106093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions Doc/library/decimal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -743,12 +743,23 @@ Decimal objects

.. method:: normalize(context=None)

Normalize the number by stripping the rightmost trailing zeros and
converting any result equal to ``Decimal('0')`` to
``Decimal('0e0')``. Used for producing canonical values for attributes
of an equivalence class. For example, ``Decimal('32.100')`` and
``Decimal('0.321000e+2')`` both normalize to the equivalent value
``Decimal('32.1')``.
Used for producing canonical values of an equivalence
class within either the current context or the specified context.

This has the same semantics as the unary plus operation, except that if
the final result is finite it is reduced to its simplest form, with all
trailing zeros removed and its sign preserved. That is, while the
coefficient is non-zero and a multiple of ten the coefficient is divided
by ten and the exponent is incremented by 1. Otherwise (the coefficient is
zero) the exponent is set to 0. In all cases the sign is unchanged.

For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both
normalize to the equivalent value ``Decimal('32.1')``.

Note that rounding is applied *before* reducing to simplest form.

In the latest versions of the specification, this operation is also known
as ``reduce``.

.. method:: number_class(context=None)

Expand Down Expand Up @@ -2078,6 +2089,26 @@ representative:
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

Q. When does rounding occur in a computation?

A. It occurs *after* the computation. The philosophy of the decimal
specification is that numbers are considered exact and are created
independent of the current context. They can even have greater
precision than current context. Computations process with those
exact inputs and then rounding (or other context operations) is
applied to the *result* of the computation::

>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')

Q. Some decimal values always print with exponential notation. Is there a way
to get a non-exponential representation?

Expand Down