PEP: 327 Title: Decimal Data Type Version: $Revision$ Last-Modified:
$Date$ Author: Facundo Batista <facundo@taniquetil.com.ar> Status: Final
Type: Standards Track Content-Type: text/x-rst Created: 17-Oct-2003
Python-Version: 2.4 Post-History: 30-Nov-2003, 02-Jan-2004, 29-Jan-2004

Abstract

The idea is to have a Decimal data type, for every use where decimals
are needed but binary floating point is too inexact.

The Decimal data type will support the Python standard functions and
operations, and must comply with the decimal arithmetic ANSI standard
X3.274-1996[1].

Decimal will be floating point (as opposed to fixed point) and will have
bounded precision (the precision is the upper limit on the number of
significant digits in a result). However, precision is user-settable,
and a notion of significant trailing zeroes is supported so that
fixed-point usage is also possible.

This work is based on code and test functions written by Eric Price,
Aahz and Tim Peters. Just before Python 2.4a1, the decimal.py reference
implementation was moved into the standard library; along with the
documentation and the test suite, this was the work of Raymond
Hettinger. Much of the explanation in this PEP is taken from Cowlishaw's
work[2], comp.lang.python and python-dev.

Motivation

Here I'll expose the reasons of why I think a Decimal data type is
needed and why other numeric data types are not enough.

I wanted a Money data type, and after proposing a pre-PEP in
comp.lang.python, the community agreed to have a numeric data type with
the needed arithmetic behaviour, and then build Money over it: all the
considerations about quantity of digits after the decimal point,
rounding, etc., will be handled through Money. It is not the purpose of
this PEP to have a data type that can be used as Money without further
effort.

One of the biggest advantages of implementing a standard is that someone
already thought out all the creepy cases for you. And to a standard GvR
redirected me: Mike Cowlishaw's General Decimal Arithmetic
specification[3]. This document defines a general purpose decimal
arithmetic. A correct implementation of this specification will conform
to the decimal arithmetic defined in ANSI/IEEE standard 854-1987, except
for some minor restrictions, and will also provide unrounded decimal
arithmetic and integer arithmetic as proper subsets.

The problem with binary float

In decimal math, there are many numbers that can't be represented with a
fixed number of decimal digits, e.g. 1/3 = 0.3333333333.......

In base 2 (the way that standard floating point is calculated), 1/2 =
0.1, 1/4 = 0.01, 1/8 = 0.001, etc. Decimal 0.2 equals 2/10 equals 1/5,
resulting in the binary fractional number 0.001100110011001... As you
can see, the problem is that some decimal numbers can't be represented
exactly in binary, resulting in small roundoff errors.

So we need a decimal data type that represents exactly decimal numbers.
Instead of a binary data type, we need a decimal one.

Why floating point?

So we go to decimal, but why floating point?

Floating point numbers use a fixed quantity of digits (precision) to
represent a number, working with an exponent when the number gets too
big or too small. For example, with a precision of 5:

    1234 ==>   1234e0
    12345 ==>  12345e0
    123456 ==>  12346e1

(note that in the last line the number got rounded to fit in five
digits).

In contrast, we have the example of a long integer with infinite
precision, meaning that you can have the number as big as you want, and
you'll never lose any information.

In a fixed point number, the position of the decimal point is fixed. For
a fixed point data type, check Tim Peter's FixedPoint at SourceForge[4].
I'll go for floating point because it's easier to implement the
arithmetic behaviour of the standard, and then you can implement a fixed
point data type over Decimal.

But why can't we have a floating point number with infinite precision?
It's not so easy, because of inexact divisions. E.g.: 1/3 =
0.3333333333333... ad infinitum. In this case you should store an
infinite amount of 3s, which takes too much memory, ;).

John Roth proposed to eliminate the division operator and force the user
to use an explicit method, just to avoid this kind of trouble. This
generated adverse reactions in comp.lang.python, as everybody wants to
have support for the / operator in a numeric data type.

With this exposed maybe you're thinking "Hey! Can we just store the 1
and the 3 as numerator and denominator?", which takes us to the next
point.

Why not rational?

Rational numbers are stored using two integer numbers, the numerator and
the denominator. This implies that the arithmetic operations can't be
executed directly (e.g. to add two rational numbers you first need to
calculate the common denominator).

Quoting Alex Martelli:

  The performance implications of the fact that summing two rationals
  (which take O(M) and O(N) space respectively) gives a rational which
  takes O(M+N) memory space is just too troublesome. There are excellent
  Rational implementations in both pure Python and as extensions (e.g.,
  gmpy), but they'll always be a "niche market" IMHO. Probably worth
  PEPping, not worth doing without Decimal -- which is the right way to
  represent sums of money, a truly major use case in the real world.

Anyway, if you're interested in this data type, you maybe will want to
take a look at PEP 239: Adding a Rational Type to Python.

So, what do we have?

The result is a Decimal data type, with bounded precision and floating
point.

Will it be useful? I can't say it better than Alex Martelli:

  Python (out of the box) doesn't let you have binary floating point
  numbers with whatever precision you specify: you're limited to what
  your hardware supplies. Decimal, be it used as a fixed or floating
  point number, should suffer from no such limitation: whatever bounded
  precision you may specify on number creation (your memory permitting)
  should work just as well. Most of the expense of programming
  simplicity can be hidden from application programs and placed in a
  suitable decimal arithmetic type. As per
  http://speleotrove.com/decimal/, a single data type can be used for
  integer, fixed-point, and floating-point decimal arithmetic -- and for
  money arithmetic which doesn't drive the application programmer crazy.

There are several uses for such a data type. As I said before, I will
use it as base for Money. In this case the bounded precision is not an
issue; quoting Tim Peters:

  A precision of 20 would be way more than enough to account for total
  world economic output, down to the penny, since the beginning of time.

General Decimal Arithmetic Specification

Here I'll include information and descriptions that are part of the
specification[5] (the structure of the number, the context, etc.). All
the requirements included in this section are not for discussion
(barring typos or other mistakes), as they are in the standard, and the
PEP is just for implementing the standard.

Because of copyright restrictions, I can not copy here explanations
taken from the specification, so I'll try to explain it in my own words.
I firmly encourage you to read the original specification document[6]
for details or if you have any doubt.

The Arithmetic Model

The specification is based on a decimal arithmetic model, as defined by
the relevant standards: IEEE 854[7], ANSI X3-274[8], and the proposed
revision[9] of IEEE 754[10].

The model has three components:

-   Numbers: just the values that the operation uses as input or output.
-   Operations: addition, multiplication, etc.
-   Context: a set of parameters and rules that the user can select and
    which govern the results of operations (for example, the precision
    to be used).

Numbers

Numbers may be finite or special values. The former can be represented
exactly. The latter are infinites and undefined (such as 0/0).

Finite numbers are defined by three parameters:

-   Sign: 0 (positive) or 1 (negative).
-   Coefficient: a non-negative integer.
-   Exponent: a signed integer, the power of ten of the coefficient
    multiplier.

The numerical value of a finite number is given by:

    (-1)**sign * coefficient * 10**exponent

Special values are named as following:

-   Infinity: a value which is infinitely large. Could be positive or
    negative.
-   Quiet NaN ("qNaN"): represent undefined results (Not a Number). Does
    not cause an Invalid operation condition. The sign in a NaN has no
    meaning.
-   Signaling NaN ("sNaN"): also Not a Number, but will cause an Invalid
    operation condition if used in any operation.

Context

The context is a set of parameters and rules that the user can select
and which govern the results of operations (for example, the precision
to be used).

The context gets that name because it surrounds the Decimal numbers,
with parts of context acting as input to, and output of, operations.
It's up to the application to work with one or several contexts, but
definitely the idea is not to get a context per Decimal number. For
example, a typical use would be to set the context's precision to 20
digits at the start of a program, and never explicitly use context
again.

These definitions don't affect the internal storage of the Decimal
numbers, just the way that the arithmetic operations are performed.

The context is mainly defined by the following parameters (see Context
Attributes for all context attributes):

-   Precision: The maximum number of significant digits that can result
    from an arithmetic operation (integer > 0). There is no maximum for
    this value.
-   Rounding: The name of the algorithm to be used when rounding is
    necessary, one of "round-down", "round-half-up", "round-half-even",
    "round-ceiling", "round-floor", "round-half-down", and "round-up".
    See Rounding Algorithms below.
-   Flags and trap-enablers: Exceptional conditions are grouped into
    signals, controllable individually, each consisting of a flag
    (boolean, set when the signal occurs) and a trap-enabler (a boolean
    that controls behavior). The signals are: "clamped",
    "division-by-zero", "inexact", "invalid-operation", "overflow",
    "rounded", "subnormal" and "underflow".

Default Contexts

The specification defines two default contexts, which should be easily
selectable by the user.

Basic Default Context:

-   flags: all set to 0
-   trap-enablers: inexact, rounded, and subnormal are set to 0; all
    others are set to 1
-   precision: is set to 9
-   rounding: is set to round-half-up

Extended Default Context:

-   flags: all set to 0
-   trap-enablers: all set to 0
-   precision: is set to 9
-   rounding: is set to round-half-even

Exceptional Conditions

The table below lists the exceptional conditions that may arise during
the arithmetic operations, the corresponding signal, and the defined
result. For details, see the specification[11].

  Condition           Signal              Result
  ------------------- ------------------- ------------------------------------------------------------------------
  Clamped             clamped             see spec[12]
  Division by zero    division-by-zero    [sign,inf]
  Inexact             inexact             unchanged
  Invalid operation   invalid-operation   [0,qNaN] (or [s,qNaN] or [s,qNaN,d] when the cause is a signaling NaN)
  Overflow            overflow            depends on the rounding mode
  Rounded             rounded             unchanged
  Subnormal           subnormal           unchanged
  Underflow           underflow           see spec[13]

Note: when the standard talks about "Insufficient storage", as long as
this is implementation-specific behaviour about not having enough
storage to keep the internals of the number, this implementation will
raise MemoryError.

Regarding Overflow and Underflow, there's been a long discussion in
python-dev about artificial limits. The general consensus is to keep the
artificial limits only if there are important reasons to do that. Tim
Peters gives us three:

  ...eliminating bounds on exponents effectively means overflow (and
  underflow) can never happen. But overflow is a valuable safety net in
  real life fp use, like a canary in a coal mine, giving danger signs
  early when a program goes insane.

  Virtually all implementations of 854 use (and as IBM's standard even
  suggests) "forbidden" exponent values to encode non-finite numbers
  (infinities and NaNs). A bounded exponent can do this at virtually no
  extra storage cost. If the exponent is unbounded, then additional bits
  have to be used instead. This cost remains hidden until more time- and
  space- efficient implementations are attempted.

  Big as it is, the IBM standard is a tiny start at supplying a complete
  numeric facility. Having no bound on exponent size will enormously
  complicate the implementations of, e.g., decimal sin() and cos()
  (there's then no a priori limit on how many digits of pi effectively
  need to be known in order to perform argument reduction).

Edward Loper give us an example of when the limits are to be crossed:
probabilities.

That said, Robert Brewer and Andrew Lentvorski want the limits to be
easily modifiable by the users. Actually, this is quite possible:

    >>> d1 = Decimal("1e999999999")     # at the exponent limit
    >>> d1
    Decimal("1E+999999999")
    >>> d1 * 10                         # exceed the limit, got infinity
    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in ?
        d1 * 10
      ...
      ...
    Overflow: above Emax
    >>> getcontext().Emax = 1000000000  # increase the limit
    >>> d1 * 10                         # does not exceed any more
    Decimal("1.0E+1000000000")
    >>> d1 * 100                        # exceed again
    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in ?
        d1 * 100
      ...
      ...
    Overflow: above Emax

Rounding Algorithms

round-down: The discarded digits are ignored; the result is unchanged
(round toward 0, truncate):

    1.123 --> 1.12
    1.128 --> 1.12
    1.125 --> 1.12
    1.135 --> 1.13

round-half-up: If the discarded digits represent greater than or equal
to half (0.5) then the result should be incremented by 1; otherwise the
discarded digits are ignored:

    1.123 --> 1.12
    1.128 --> 1.13
    1.125 --> 1.13
    1.135 --> 1.14

round-half-even: If the discarded digits represent greater than half
(0.5) then the result coefficient is incremented by 1; if they represent
less than half, then the result is not adjusted; otherwise the result is
unaltered if its rightmost digit is even, or incremented by 1 if its
rightmost digit is odd (to make an even digit):

    1.123 --> 1.12
    1.128 --> 1.13
    1.125 --> 1.12
    1.135 --> 1.14

round-ceiling: If all of the discarded digits are zero or if the sign is
negative the result is unchanged; otherwise, the result is incremented
by 1 (round toward positive infinity):

    1.123 -->  1.13
    1.128 -->  1.13
    -1.123 --> -1.12
    -1.128 --> -1.12

round-floor: If all of the discarded digits are zero or if the sign is
positive the result is unchanged; otherwise, the absolute value of the
result is incremented by 1 (round toward negative infinity):

    1.123 -->  1.12
    1.128 -->  1.12
    -1.123 --> -1.13
    -1.128 --> -1.13

round-half-down: If the discarded digits represent greater than half
(0.5) then the result is incremented by 1; otherwise the discarded
digits are ignored:

    1.123 --> 1.12
    1.128 --> 1.13
    1.125 --> 1.12
    1.135 --> 1.13

round-up: If all of the discarded digits are zero the result is
unchanged, otherwise the result is incremented by 1 (round away from 0):

    1.123 --> 1.13
    1.128 --> 1.13
    1.125 --> 1.13
    1.135 --> 1.14

Rationale

I must separate the requirements in two sections. The first is to comply
with the ANSI standard. All the requirements for this are specified in
the Mike Cowlishaw's work[14]. He also provided a very large suite of
test cases.

The second section of requirements (standard Python functions support,
usability, etc.) is detailed from here, where I'll include all the
decisions made and why, and all the subjects still being discussed.

Explicit construction

The explicit construction does not get affected by the context (there is
no rounding, no limits by the precision, etc.), because the context
affects just operations' results. The only exception to this is when
you're Creating from Context.

From int or long

There's no loss and no need to specify any other information:

    Decimal(35)
    Decimal(-124)

From string

Strings containing Python decimal integer literals and Python float
literals will be supported. In this transformation there is no loss of
information, as the string is directly converted to Decimal (there is
not an intermediate conversion through float):

    Decimal("-12")
    Decimal("23.2e-7")

Also, you can construct in this way all special values (Infinity and Not
a Number):

    Decimal("Inf")
    Decimal("NaN")

From float

The initial discussion on this item was what should happen when passing
floating point to the constructor:

1.  Decimal(1.1) == Decimal('1.1')
2.  Decimal(1.1) == Decimal('110000000000000008881784197001252...e-51')
3.  an exception is raised

Several people alleged that (1) is the better option here, because it's
what you expect when writing Decimal(1.1). And quoting John Roth, it's
easy to implement:

  It's not at all difficult to find where the actual number ends and
  where the fuzz begins. You can do it visually, and the algorithms to
  do it are quite well known.

But If I really want my number to be
Decimal('110000000000000008881784197001252...e-51'), why can't I write
Decimal(1.1)? Why should I expect Decimal to be "rounding" it? Remember
that 1.1 is binary floating point, so I can predict the result. It's not
intuitive to a beginner, but that's the way it is.

Anyway, Paul Moore showed that (1) can't work, because:

    (1) says  D(1.1) == D('1.1')
    but       1.1 == 1.1000000000000001
    so        D(1.1) == D(1.1000000000000001)
    together: D(1.1000000000000001) == D('1.1')

which is wrong, because if I write Decimal('1.1') it is exact, not
D(1.1000000000000001). He also proposed to have an explicit conversion
to float. bokr says you need to put the precision in the constructor and
mwilson agreed:

    d = Decimal (1.1, 1)  # take float value to 1 decimal place
    d = Decimal (1.1)  # gets `places` from pre-set context

But Alex Martelli says that:

  Constructing with some specified precision would be fine. Thus, I
  think "construction from float with some default precision" runs a
  substantial risk of tricking naive users.

So, the accepted solution through c.l.p is that you can not call Decimal
with a float. Instead you must use a method: Decimal.from_float(). The
syntax:

    Decimal.from_float(floatNumber, [decimal_places])

where floatNumber is the float number origin of the construction and
decimal_places are the number of digits after the decimal point where
you apply a round-half-up rounding, if any. In this way you can do, for
example:

    Decimal.from_float(1.1, 2): The same as doing Decimal('1.1').
    Decimal.from_float(1.1, 16): The same as doing Decimal('1.1000000000000001').
    Decimal.from_float(1.1): The same as doing Decimal('1100000000000000088817841970012523233890533447265625e-51').

Based on later discussions, it was decided to omit from_float() from the
API for Py2.4. Several ideas contributed to the thought process:

-   Interactions between decimal and binary floating point force the
    user to deal with tricky issues of representation and round-off.
    Avoidance of those issues is a primary reason for having the module
    in the first place.

-   The first release of the module should focus on that which is safe,
    minimal, and essential.

-   While theoretically nice, real world use cases for interactions
    between floats and decimals are lacking. Java included float/decimal
    conversions to handle an obscure case where calculations are best
    performed in decimal even though a legacy data structure requires
    the inputs and outputs to be stored in binary floating point.

-   If the need arises, users can use string representations as an
    intermediate type. The advantage of this approach is that it makes
    explicit the assumptions about precision and representation (no
    wondering what is going on under the hood).

-   The Java docs for BigDecimal(double val) reflected their experiences
    with the constructor:

        The results of this constructor can be somewhat
        unpredictable and its use is generally not recommended.

From tuples

Aahz suggested to construct from tuples: it's easier to implement
eval()'s round trip and "someone who has numeric values representing a
Decimal does not need to convert them to a string."

The structure will be a tuple of three elements: sign, number and
exponent. The sign is 1 or 0, the number is a tuple of decimal digits
and the exponent is a signed int or long:

    Decimal((1, (3, 2, 2, 5), -2))     # for -32.25

Of course, you can construct in this way all special values:

    Decimal( (0, (0,), 'F') )          # for Infinity
    Decimal( (0, (0,), 'n') )          # for Not a Number

From Decimal

No mystery here, just a copy.

Syntax for All Cases

    Decimal(value1)
    Decimal.from_float(value2, [decimal_places])

where value1 can be int, long, string, 3-tuple or Decimal, value2 can
only be float, and decimal_places is an optional non negative int.

Creating from Context

This item arose in python-dev from two sources in parallel. Ka-Ping Yee
proposes to pass the context as an argument at instance creation (he
wants the context he passes to be used only in creation time: "It would
not be persistent"). Tony Meyer asks from_string to honor the context if
it receives a parameter "honour_context" with a True value. (I don't
like it, because the doc specifies that the context be honored and I
don't want the method to comply with the specification regarding the
value of an argument.)

Tim Peters gives us a reason to have a creation that uses context:

  In general number-crunching, literals may be given to high precision,
  but that precision isn't free and usually isn't needed

Casey Duncan wants to use another method, not a bool arg:

  I find boolean arguments a general anti-pattern, especially given we
  have class methods. Why not use an alternate constructor like
  Decimal.rounded_to_context("3.14159265").

In the process of deciding the syntax of that, Tim came up with a better
idea: he proposes not to have a method in Decimal to create with a
different context, but having instead a method in Context to create a
Decimal instance. Basically, instead of:

    D.using_context(number, context)

it will be:

    context.create_decimal(number)

From Tim:

  While all operations in the spec except for the two to-string
  operations use context, no operations in the spec support an optional
  local context. That the Decimal() constructor ignores context by
  default is an extension to the spec. We must supply a context-honoring
  from-string operation to meet the spec. I recommend against any
  concept of "local context" in any operation -- it complicates the
  model and isn't necessary.

So, we decided to use a context method to create a Decimal that will use
(only to be created) that context in particular (for further operations
it will use the context of the thread). But, a method with what name?

Tim Peters proposes three methods to create from diverse sources
(from_string, from_int, from_float). I proposed to use one method,
create_decimal(), without caring about the data type. Michael Chermside:
"The name just fits my brain. The fact that it uses the context is
obvious from the fact that it's Context method".

The community agreed with that. I think that it's OK because a newbie
will not be using the creation method from Context (the separate method
in Decimal to construct from float is just to prevent newbies from
encountering binary floating point issues).

So, in short, if you want to create a Decimal instance using a
particular context (that will be used just at creation time and not any
further), you'll have to use a method of that context:

    # n is any datatype accepted in Decimal(n) plus float
    mycontext.create_decimal(n)

Example:

    >>> # create a standard decimal instance
    >>> Decimal("11.2233445566778899")
    Decimal("11.2233445566778899")
    >>>
    >>> # create a decimal instance using the thread context
    >>> thread_context = getcontext()
    >>> thread_context.prec
    28
    >>> thread_context.create_decimal("11.2233445566778899")
    Decimal("11.2233445566778899")
    >>>
    >>> # create a decimal instance using other context
    >>> other_context = thread_context.copy()
    >>> other_context.prec = 4
    >>> other_context.create_decimal("11.2233445566778899")
    Decimal("11.22")

Implicit construction

As the implicit construction is the consequence of an operation, it will
be affected by the context as is detailed in each point.

John Roth suggested that "The other type should be handled in the same
way the decimal() constructor would handle it". But Alex Martelli thinks
that

  this total breach with Python tradition would be a terrible mistake.
  23+"43" is NOT handled in the same way as 23+int("45"), and a VERY
  good thing that is too. It's a completely different thing for a user
  to EXPLICITLY indicate they want construction (conversion) and to just
  happen to sum two objects one of which by mistake could be a string.

So, here I define the behaviour again for each data type.

From int or long

An int or long is a treated like a Decimal explicitly constructed from
Decimal(str(x)) in the current context (meaning that the to-string rules
for rounding are applied and the appropriate flags are set). This
guarantees that expressions like Decimal('1234567') + 13579 match the
mental model of Decimal('1234567') + Decimal('13579'). That model works
because all integers are representable as strings without representation
error.

From string

Everybody agrees to raise an exception here.

From float

Aahz is strongly opposed to interact with float, suggesting an explicit
conversion:

  The problem is that Decimal is capable of greater precision, accuracy,
  and range than float.

The example of the valid python expression, 35 + 1.1, seems to suggest
that Decimal(35) + 1.1 should also be valid. However, a closer look
shows that it only demonstrates the feasibility of integer to floating
point conversions. Hence, the correct analog for decimal floating point
is 35 + Decimal(1.1). Both coercions, int-to-float and int-to-Decimal,
can be done without incurring representation error.

The question of how to coerce between binary and decimal floating point
is more complex. I proposed allowing the interaction with float, making
an exact conversion and raising ValueError if exceeds the precision in
the current context (this is maybe too tricky, because for example with
a precision of 9, Decimal(35) + 1.2 is OK but Decimal(35) + 1.1 raises
an error).

This resulted to be too tricky. So tricky, that c.l.p agreed to raise
TypeError in this case: you could not mix Decimal and float.

From Decimal

There isn't any issue here.

Use of Context

In the last pre-PEP I said that "The Context must be omnipresent,
meaning that changes to it affects all the current and future Decimal
instances". I was wrong. In response, John Roth said:

  The context should be selectable for the particular usage. That is, it
  should be possible to have several different contexts in play at one
  time in an application.

In comp.lang.python, Aahz explained that the idea is to have a "context
per thread". So, all the instances of a thread belongs to a context, and
you can change a context in thread A (and the behaviour of the instances
of that thread) without changing nothing in thread B.

Also, and again correcting me, he said:

  (the) Context applies only to operations, not to Decimal instances;
  changing the Context does not affect existing instances if there are
  no operations on them.

Arguing about special cases when there's need to perform operations with
other rules that those of the current context, Tim Peters said that the
context will have the operations as methods. This way, the user "can
create whatever private context object(s) it needs, and spell arithmetic
as explicit method calls on its private context object(s), so that the
default thread context object is neither consulted nor modified".

Python Usability

-   Decimal should support the basic arithmetic
    (+, -, *, /, //, **, %, divmod) and comparison
    (==, !=, <, >, <=, >=, cmp) operators in the following cases (check
    Implicit Construction to see what types could OtherType be, and what
    happens in each case):

    -   Decimal op Decimal
    -   Decimal op otherType
    -   otherType op Decimal
    -   Decimal op= Decimal
    -   Decimal op= otherType

-   Decimal should support unary operators (-, +, abs).

-   repr() should round trip, meaning that:

        m = Decimal(...)
        m == eval(repr(m))

-   Decimal should be immutable.

-   Decimal should support the built-in methods:

    -   min, max
    -   float, int, long
    -   str, repr
    -   hash
    -   bool (0 is false, otherwise true)

There's been some discussion in python-dev about the behaviour of
hash(). The community agrees that if the values are the same, the hashes
of those values should also be the same. So, while Decimal(25) == 25 is
True, hash(Decimal(25)) should be equal to hash(25).

The detail is that you can NOT compare Decimal to floats or strings, so
we should not worry about them giving the same hashes. In short:

    hash(n) == hash(Decimal(n))   # Only if n is int, long, or Decimal

Regarding str() and repr() behaviour, Ka-Ping Yee proposes that repr()
have the same behaviour as str() and Tim Peters proposes that str()
behave like the to-scientific-string operation from the Spec.

This is possible, because (from Aahz): "The string form already contains
all the necessary information to reconstruct a Decimal object".

And it also complies with the Spec; Tim Peters:

  There's no requirement to have a method named "to_sci_string", the
  only requirement is that some way to spell to-sci-string's
  functionality be supplied. The meaning of to-sci-string is precisely
  specified by the standard, and is a good choice for both str(Decimal)
  and repr(Decimal).

Documentation

This section explains all the public methods and attributes of Decimal
and Context.

Decimal Attributes

Decimal has no public attributes. The internal information is stored in
slots and should not be accessed by end users.

Decimal Methods

Following are the conversion and arithmetic operations defined in the
Spec, and how that functionality can be achieved with the actual
implementation.

-   to-scientific-string: Use builtin function str():

        >>> d = Decimal('123456789012.345')
        >>> str(d)
        '1.23456789E+11'

-   to-engineering-string: Use method to_eng_string():

        >>> d = Decimal('123456789012.345')
        >>> d.to_eng_string()
        '123.456789E+9'

-   to-number: Use Context method create_decimal(). The standard
    constructor or from_float() constructor cannot be used because these
    do not use the context (as is specified in the Spec for this
    conversion).

-   abs: Use builtin function abs():

        >>> d = Decimal('-15.67')
        >>> abs(d)
        Decimal('15.67')

-   add: Use operator +:

        >>> d = Decimal('15.6')
        >>> d + 8
        Decimal('23.6')

-   subtract: Use operator -:

        >>> d = Decimal('15.6')
        >>> d - 8
        Decimal('7.6')

-   compare: Use method compare(). This method (and not the built-in
    function cmp()) should only be used when dealing with special
    values:

        >>> d = Decimal('-15.67')
        >>> nan = Decimal('NaN')
        >>> d.compare(23)
        '-1'
        >>> d.compare(nan)
        'NaN'
        >>> cmp(d, 23)
        -1
        >>> cmp(d, nan)
        1

-   divide: Use operator /:

        >>> d = Decimal('-15.67')
        >>> d / 2
        Decimal('-7.835')

-   divide-integer: Use operator //:

        >>> d = Decimal('-15.67')
        >>> d // 2
        Decimal('-7')

-   max: Use method max(). Only use this method (and not the built-in
    function max()) when dealing with special values:

        >>> d = Decimal('15')
        >>> nan = Decimal('NaN')
        >>> d.max(8)
        Decimal('15')
        >>> d.max(nan)
        Decimal('NaN')

-   min: Use method min(). Only use this method (and not the built-in
    function min()) when dealing with special values:

        >>> d = Decimal('15')
        >>> nan = Decimal('NaN')
        >>> d.min(8)
        Decimal('8')
        >>> d.min(nan)
        Decimal('NaN')

-   minus: Use unary operator -:

        >>> d = Decimal('-15.67')
        >>> -d
        Decimal('15.67')

-   plus: Use unary operator +:

        >>> d = Decimal('-15.67')
        >>> +d
        Decimal('-15.67')

-   multiply: Use operator *:

        >>> d = Decimal('5.7')
        >>> d * 3
        Decimal('17.1')

-   normalize: Use method normalize():

        >>> d = Decimal('123.45000')
        >>> d.normalize()
        Decimal('123.45')
        >>> d = Decimal('120.00')
        >>> d.normalize()
        Decimal('1.2E+2')

-   quantize: Use method quantize():

        >>> d = Decimal('2.17')
        >>> d.quantize(Decimal('0.001'))
        Decimal('2.170')
        >>> d.quantize(Decimal('0.1'))
        Decimal('2.2')

-   remainder: Use operator %:

        >>> d = Decimal('10')
        >>> d % 3
        Decimal('1')
        >>> d % 6
        Decimal('4')

-   remainder-near: Use method remainder_near():

        >>> d = Decimal('10')
        >>> d.remainder_near(3)
        Decimal('1')
        >>> d.remainder_near(6)
        Decimal('-2')

-   round-to-integral-value: Use method to_integral():

        >>> d = Decimal('-123.456')
        >>> d.to_integral()
        Decimal('-123')

-   same-quantum: Use method same_quantum():

        >>> d = Decimal('123.456')
        >>> d.same_quantum(Decimal('0.001'))
        True
        >>> d.same_quantum(Decimal('0.01'))
        False

-   square-root: Use method sqrt():

        >>> d = Decimal('123.456')
        >>> d.sqrt()
        Decimal('11.1110756')

-   power: User operator **:

        >>> d = Decimal('12.56')
        >>> d ** 2
        Decimal('157.7536')

Following are other methods and why they exist:

-   adjusted(): Returns the adjusted exponent. This concept is defined
    in the Spec: the adjusted exponent is the value of the exponent of a
    number when that number is expressed as though in scientific
    notation with one digit before any decimal point:

        >>> d = Decimal('12.56')
        >>> d.adjusted()
        1

-   from_float(): Class method to create instances from float data
    types:

        >>> d = Decimal.from_float(12.35)
        >>> d
        Decimal('12.3500000')

-   as_tuple(): Show the internal structure of the Decimal, the triple
    tuple. This method is not required by the Spec, but Tim Peters
    proposed it and the community agreed to have it (it's useful for
    developing and debugging):

        >>> d = Decimal('123.4')
        >>> d.as_tuple()
        (0, (1, 2, 3, 4), -1)
        >>> d = Decimal('-2.34e5')
        >>> d.as_tuple()
        (1, (2, 3, 4), 3)

Context Attributes

These are the attributes that can be changed to modify the context.

-   prec (int): the precision:

        >>> c.prec
        9

-   rounding (str): rounding type (how to round):

        >>> c.rounding
        'half_even'

-   trap_enablers (dict): if trap_enablers[exception] = 1, then an
    exception is raised when it is caused:

        >>> c.trap_enablers[Underflow]
        0
        >>> c.trap_enablers[Clamped]
        0

-   flags (dict): when an exception is caused, flags[exception] is
    incremented (whether or not the trap_enabler is set). Should be
    reset by the user of Decimal instance:

        >>> c.flags[Underflow]
        0
        >>> c.flags[Clamped]
        0

-   Emin (int): minimum exponent:

        >>> c.Emin
        -999999999

-   Emax (int): maximum exponent:

        >>> c.Emax
        999999999

-   capitals (int): boolean flag to use 'E' (True/1) or 'e' (False/0) in
    the string (for example, '1.32e+2' or '1.32E+2'):

        >>> c.capitals
        1

Context Methods

The following methods comply with Decimal functionality from the Spec.
Be aware that the operations that are called through a specific context
use that context and not the thread context.

To use these methods, take note that the syntax changes when the
operator is binary or unary, for example:

    >>> mycontext.abs(Decimal('-2'))
    '2'
    >>> mycontext.multiply(Decimal('2.3'), 5)
    '11.5'

So, the following are the Spec operations and conversions and how to
achieve them through a context (where d is a Decimal instance and n a
number that can be used in an Implicit construction):

-   to-scientific-string: to_sci_string(d)
-   to-engineering-string: to_eng_string(d)
-   to-number: create_decimal(number), see Explicit construction for
    number.
-   abs: abs(d)
-   add: add(d, n)
-   subtract: subtract(d, n)
-   compare: compare(d, n)
-   divide: divide(d, n)
-   divide-integer: divide_int(d, n)
-   max: max(d, n)
-   min: min(d, n)
-   minus: minus(d)
-   plus: plus(d)
-   multiply: multiply(d, n)
-   normalize: normalize(d)
-   quantize: quantize(d, d)
-   remainder: remainder(d)
-   remainder-near: remainder_near(d)
-   round-to-integral-value: to_integral(d)
-   same-quantum: same_quantum(d, d)
-   square-root: sqrt(d)
-   power: power(d, n)

The divmod(d, n) method supports decimal functionality through Context.

These are methods that return useful information from the Context:

-   Etiny(): Minimum exponent considering precision. :

        >>> c.Emin
        -999999999
        >>> c.Etiny()
        -1000000007

-   Etop(): Maximum exponent considering precision. :

        >>> c.Emax
        999999999
        >>> c.Etop()
        999999991

-   copy(): Returns a copy of the context.

Reference Implementation

As of Python 2.4-alpha, the code has been checked into the standard
library. The latest version is available from:

http://svn.python.org/view/python/trunk/Lib/decimal.py

The test cases are here:

http://svn.python.org/view/python/trunk/Lib/test/test_decimal.py

References

Copyright

This document has been placed in the public domain.



  Local Variables: mode: indented-text indent-tabs-mode: nil
  sentence-end-double-space: t fill-column: 70 End:

[1] ANSI standard X3.274-1996 (Programming Language REXX):
http://www.rexxla.org/Standards/ansi.html

[2] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[3] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[4] Tim Peter's FixedPoint at SourceForge:
http://fixedpoint.sourceforge.net/

[5] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[6] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[7] ANSI/IEEE standard 854-1987 (Radix-Independent Floating-Point
Arithmetic):
http://www.cs.berkeley.edu/~ejr/projects/754/private/drafts/854-1987/dir.html
(unofficial text; official copies can be ordered from
http://standards.ieee.org/catalog/ordering.html)

[8] ANSI standard X3.274-1996 (Programming Language REXX):
http://www.rexxla.org/Standards/ansi.html

[9] IEEE 754 revision: http://grouper.ieee.org/groups/754/revision.html

[10] IEEE 754 references:
http://babbage.cs.qc.edu/courses/cs341/IEEE-754references.html

[11] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[12] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[13] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)

[14] General Decimal Arithmetic specification (Cowlishaw):
http://speleotrove.com/decimal/decarith.html (related documents and
links at http://speleotrove.com/decimal/)