B
Batista, Facundo
Here I send it.
Suggestions and all kinds of recomendations are more than welcomed.
If it all goes ok, it'll be a PEP when I finish writing/modifying the code.
Thank you.
.. Facundo
------------------------------------------------------------------------
PEP: XXXX
Title: Decimal data type
Version: $Revision: 0.1 $
Last-Modified: $Date: 2003/10/31 15:25:00 $
Author: Facundo Batista <[email protected]>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 17-Oct-2003
Python-Version: 2.3.3
Abstract
========
The idea is to have a Decimal data type, for every use where decimals are
needed but floating point is too inexact.
The Decimal data type should support the Python standard functions and
operations and must comply the decimal arithmetic ANSI standard X3.274-1996.
Rationale
=========
I must separate the requeriments in two sections. The first is to comply
with the ANSI standard. All the needings for this are specified in the
Mike Cowlishaw's work at http://www2.hursley.ibm.com/decimal/. Cowlishaw's
also provided a **lot** of test cases. The second section of requeriments
(standard Python functions support, usability, etc) are detailed in the
`Requirements`_ section.
Here I'll include all the decisions made and why, and all the subjects still
being discussed. The requirements will be numbered, to simplify discussion
on each point.
This work is based on code and test functions written by Eric Price, Aahz
and
Tim Peters. Actually I'll work on the Decimal.py code in the sandbox (at
python/nondist/sandbox/decimal in SourceForge). Some of the explanations of
this PEP are taken from the Cowlishaw's work.
Items In Discussion
-------------------
When in a case like ``Decimal op otherType`` (see point 12 in Requirements_
for details), what should happen?
if otherType is an int or long:
a. an exception is raised
b. otherType is converted to Decimal
c. Decimal is converted to int or long (with ``int()`` or
``long()``)
if otherType is a float:
d. an exception is raised
e. otherType is converted to Decimal (rounding? see next item in
discussion)
f. Decimal is converted to float (with ``float()``)
if otherType is a string:
g. an exception is raised
h. otherType is converted to Decimal
i. Decimal is converted to string (bizarre, huh?)
When passing floating point to the constructor, what should happen?
j. ``Decimal(1.1) == Decimal('1.1')``
k. ``Decimal(1.1) ==
Decimal('110000000000000008881784197001252...e-51')``
Requirements
============
1. The syntax should be ``Decimal(value)``.
2. The value could be of the type:
- another Decimal
- int or long
- float
- string
3. To exist a Context. The context represents the user-selectable
parameters
and rules which govern the results of arithmetic operations. In the
context the user defines:
- what will happen with the exceptional conditions.
- what precision will be used
- what rounding method will be used
4. The Context must be omnipresent, meaning that changes to it affects all
the current and future Decimal instances.
5. The exceptional conditions should be grouped into signals, which could be
controlled individually. The context should contain a flag and a
trap-enabler for each signal. The signals should be: clamped,
division-by-zero, inexact, invalid-operation, overflow, rounded,
subnormal
and underflow.
6. For each of the signals, the corresponding flag should be set to 1 when
the signal occurs. It is only reset to 0 by explicit user action.
7. For each of the signals, the corresponding trap-enabler will indicate
which action is to be taken when the signal occurs. If 0, a defined
result should be supplied, and execution should continue. If 1, the
execution of the operation should end and an exception should be raised.
8. The precision (maximum number of significant digits that can result from
an arithmetic operation) must be positive (greater than 0).
9. To have different kinds of rounding; you can choose the algorithm through
context:
- ``round-down``: (Round toward 0, truncate) The discarded digits are
ignored; the result is unchanged::
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
(rounded up); 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 should be incremented by 1
(rounded up); if they represent less than half, then the result is
not adjusted (that is, the discarded digits are ignored); otherwise
the result is unaltered if its rightmost digit is even, or
incremented by 1 (rounded up) 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
should be incremented by 1 (rounded up)::
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 should be incremented by 1::
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 should be incremented by 1 (rounded up);
otherwise the discarded digits are ignored::
1.123 --> 1.12
1.128 --> 1.13
1.125 --> 1.12
1.135 --> 1.13
- ``round-up``: (Round away from 0) If all of the discarded digits
are
zero the result is unchanged. Otherwise, the result should be
incremented by 1 (rounded up)::
1.123 --> 1.13
1.128 --> 1.13
1.125 --> 1.13
1.135 --> 1.14
10. Strings with floats in engineering notation will be supported.
11. Calling repr() should do round trip, meaning that::
m = Decimal(...)
m == eval(repr(m))
12. To support the basic aritmetic (``+, -, *, /, //, **, %, divmod``) and
comparison (``==, !=, <, >, <=, >=, cmp``) operators in the following
cases:
- Decimal op Decimal
- Decimal op otherType
- otherType op Decimal
- Decimal op= Decimal
- Decimal op= otherType
Check `Items In Discussion`_ to see what types could OtherType be, and
what happens in each case.
13. To support unary operators (``-, +, abs``).
14. To support the built-in methods:
- min, max
- float, int, long
- str, repr
- hash
- copy, deepcopy
- bool (0 is false, otherwise true)
15. To be immutable.
Reference Implementation
========================
To be included later:
- code
- test code
- documentation
Copyright
=========
This document has been placed in the public domain.
Suggestions and all kinds of recomendations are more than welcomed.
If it all goes ok, it'll be a PEP when I finish writing/modifying the code.
Thank you.
.. Facundo
------------------------------------------------------------------------
PEP: XXXX
Title: Decimal data type
Version: $Revision: 0.1 $
Last-Modified: $Date: 2003/10/31 15:25:00 $
Author: Facundo Batista <[email protected]>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 17-Oct-2003
Python-Version: 2.3.3
Abstract
========
The idea is to have a Decimal data type, for every use where decimals are
needed but floating point is too inexact.
The Decimal data type should support the Python standard functions and
operations and must comply the decimal arithmetic ANSI standard X3.274-1996.
Rationale
=========
I must separate the requeriments in two sections. The first is to comply
with the ANSI standard. All the needings for this are specified in the
Mike Cowlishaw's work at http://www2.hursley.ibm.com/decimal/. Cowlishaw's
also provided a **lot** of test cases. The second section of requeriments
(standard Python functions support, usability, etc) are detailed in the
`Requirements`_ section.
Here I'll include all the decisions made and why, and all the subjects still
being discussed. The requirements will be numbered, to simplify discussion
on each point.
This work is based on code and test functions written by Eric Price, Aahz
and
Tim Peters. Actually I'll work on the Decimal.py code in the sandbox (at
python/nondist/sandbox/decimal in SourceForge). Some of the explanations of
this PEP are taken from the Cowlishaw's work.
Items In Discussion
-------------------
When in a case like ``Decimal op otherType`` (see point 12 in Requirements_
for details), what should happen?
if otherType is an int or long:
a. an exception is raised
b. otherType is converted to Decimal
c. Decimal is converted to int or long (with ``int()`` or
``long()``)
if otherType is a float:
d. an exception is raised
e. otherType is converted to Decimal (rounding? see next item in
discussion)
f. Decimal is converted to float (with ``float()``)
if otherType is a string:
g. an exception is raised
h. otherType is converted to Decimal
i. Decimal is converted to string (bizarre, huh?)
When passing floating point to the constructor, what should happen?
j. ``Decimal(1.1) == Decimal('1.1')``
k. ``Decimal(1.1) ==
Decimal('110000000000000008881784197001252...e-51')``
Requirements
============
1. The syntax should be ``Decimal(value)``.
2. The value could be of the type:
- another Decimal
- int or long
- float
- string
3. To exist a Context. The context represents the user-selectable
parameters
and rules which govern the results of arithmetic operations. In the
context the user defines:
- what will happen with the exceptional conditions.
- what precision will be used
- what rounding method will be used
4. The Context must be omnipresent, meaning that changes to it affects all
the current and future Decimal instances.
5. The exceptional conditions should be grouped into signals, which could be
controlled individually. The context should contain a flag and a
trap-enabler for each signal. The signals should be: clamped,
division-by-zero, inexact, invalid-operation, overflow, rounded,
subnormal
and underflow.
6. For each of the signals, the corresponding flag should be set to 1 when
the signal occurs. It is only reset to 0 by explicit user action.
7. For each of the signals, the corresponding trap-enabler will indicate
which action is to be taken when the signal occurs. If 0, a defined
result should be supplied, and execution should continue. If 1, the
execution of the operation should end and an exception should be raised.
8. The precision (maximum number of significant digits that can result from
an arithmetic operation) must be positive (greater than 0).
9. To have different kinds of rounding; you can choose the algorithm through
context:
- ``round-down``: (Round toward 0, truncate) The discarded digits are
ignored; the result is unchanged::
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
(rounded up); 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 should be incremented by 1
(rounded up); if they represent less than half, then the result is
not adjusted (that is, the discarded digits are ignored); otherwise
the result is unaltered if its rightmost digit is even, or
incremented by 1 (rounded up) 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
should be incremented by 1 (rounded up)::
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 should be incremented by 1::
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 should be incremented by 1 (rounded up);
otherwise the discarded digits are ignored::
1.123 --> 1.12
1.128 --> 1.13
1.125 --> 1.12
1.135 --> 1.13
- ``round-up``: (Round away from 0) If all of the discarded digits
are
zero the result is unchanged. Otherwise, the result should be
incremented by 1 (rounded up)::
1.123 --> 1.13
1.128 --> 1.13
1.125 --> 1.13
1.135 --> 1.14
10. Strings with floats in engineering notation will be supported.
11. Calling repr() should do round trip, meaning that::
m = Decimal(...)
m == eval(repr(m))
12. To support the basic aritmetic (``+, -, *, /, //, **, %, divmod``) and
comparison (``==, !=, <, >, <=, >=, cmp``) operators in the following
cases:
- Decimal op Decimal
- Decimal op otherType
- otherType op Decimal
- Decimal op= Decimal
- Decimal op= otherType
Check `Items In Discussion`_ to see what types could OtherType be, and
what happens in each case.
13. To support unary operators (``-, +, abs``).
14. To support the built-in methods:
- min, max
- float, int, long
- str, repr
- hash
- copy, deepcopy
- bool (0 is false, otherwise true)
15. To be immutable.
Reference Implementation
========================
To be included later:
- code
- test code
- documentation
Copyright
=========
This document has been placed in the public domain.