Source

python-peps / pep-0327.txt

The default branch has multiple heads

Full commit
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
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 [2]_.  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 a
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 [2]_ (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 [2]_ 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 [3]_, ANSI X3-274 [1]_, and the
proposed revision [5]_ of IEEE 754 [6]_.

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 [2]_.

====================  =================  ===================================
Condition             Signal             Result
====================  =================  ===================================
Clamped               clamped            see spec [2]_
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 [2]_
====================  =================  ===================================

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 posible::

    >>> 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
infinty)::

     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 [2]_.  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 eventhough
  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 posible, 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
==========

.. [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] 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)

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

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

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


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: