Search code examples
pythonpython-3.xdecimal

When is a decimal considered as 'canonical'?


Everywhere on the Internet it always says the decimal.Decimal.is_canonical() method will return True if the decimal is canonical.

But what does that even mean? Is it just some term that I do not know?


Solution

  • Contrary to what the other answer claims, canonical is not related to normalize. "Canonical" as used in the normalize docs is not the same as in the canonical or is_canonical methods - if it were the same, then normalize would always return its argument unchanged, as Decimal instances are always canonical as far as is_canonical is concerned.

    The decimal module is an implementation of the IBM General Decimal Arithmetic Specification, and Decimal.is_canonical exists for the sole purpose of implementing that specification's is-canonical operation. The spec has this to say about is-canonical:

    is-canonical takes one operand. The result is 1 if the operand is canonical; otherwise it is 0. The definition of canonical is implementation-defined; if more than one internal encoding for a given NaN, Infinity, or finite number is possible then one ‘preferred’ encoding is deemed canonical. This operation then tests whether the internal encoding is that preferred encoding.

    If all possible operands have just one internal encoding each, then is-canonical always returns 1. This operation is unaffected by context and is quiet – no flags are changed in the context.

    If an implementation of the spec has multiple internal encodings of a value, then one encoding is deemed canonical, and is_canonical tests whether a value is encoded that way. If an implementation (like Python's decimal module) does not have multiple encodings of the same value, then the operation always reports that the operand is canonical.

    Note that the way the spec defines "finite number", Decimal('2.50') and Decimal('2.5') are different finite numbers, not different internal encodings of the same number. Finite numbers are defined by a sign, coefficient, and exponent, not by their numerical value. 2.50 has coefficient 250 and exponent -2, while 2.5 has coefficient 25 and exponent -1. Thus, there is no problem with is_canonical reporting True for both of these instances.