prePEP: Decimal data type

Alex Martelli aleax at aleax.it
Sat Nov 1 13:24:44 EST 2003


John Roth wrote:
   ...
> Alex, where did I suggest that I wanted a rational data type? Please
> tell me one place in my response where I said that. Please?

You fought against limited precision, and said NOTHING against
the requirement that the new type support division (point 12 in
the specs).  This implies the implementation must use rationals
(by any other name).  Of course, if you now change your responses
(and in particular change the lack of objection to / into a
request that it be abrogated, as you do below) then (at least
some of) the objections to your proposals change (the one against
the crazy idea of having number+string implicitly convert the
string "just as if" it had been explicitly converted stands, of
course -- "if you want Perl, you know where to find it").


> For the record. I'm not suggesting a rational data type. I'm quite
> well aware of the arguements pro and con, and Guido's position.
> Please read what I said without your preconceptions.

I have no preconceptions about what your opinions of various
number kinds may be: I simply read your post, and if in that
post you say *NOT A WORD* against division, how can you expect
any reader to divine that you want to abolish it?!  Cheez --
what about learning to write, rather than chiding others for
not reading your mind but rather just reading what you write
and what you _don't_ write?!


> The only place where you can get into trouble is with division
> and equivalent operations. That's the one place where you actually

If one accepts that an arbitrary float is somehow (perhaps a bit
arbitrarily) coerced into a decimal-fraction before operating
(e.g. by multiplication) -- or forbids such mixed-type operations,
against your expressed wishes -- yes.

The resulting decimal type, however, may not be highly usable
for some kinds of monetary computations.  It's an unfortunate
but undisputable fact of life that laws and regulations exist
that specify some monetary computations in detailed ways that
differ from each other.  E.g., in the EU all computations must
be carried out to the hundredth of an Euro, no less and *no
more*, with rounding as specified in the regulations (I quoted
them extensively in the preceding python-dev discussion which
you may find in the archives) -- the laws indicate that this
may give "off by one cent" results compared with exact arithmetic,
with examples, and mandate that this one-cent difference be
accepted as it derives from application of their exact rules
(they even specifically note that reconciling accounts will be
made too hard unless computer programs and similar equipment
all follow these exact rumes).  Other jurisdictions have
different rules and regulations -- e.g., not sure if there still
are such markets, but once US financial markets mandated the
accounting to be in 1/16th of a dollar (which is _not_ the same
thing as arithmetic in hundredths of a cent -- most values you
might obtain with the latter are not valid in the former).

Say that a charge that is specified by law as 2.6473% is to be
computed on each unit of a stock currently worth 2.33 currency
units.  The resulting "exact" amount of 0.06168209 must be
treated as "exactly" 6 Eurocents in the EU; this will cause an
off-by-one (and thus by a lot depending how many units of stock
you have), but if this is the computation the law specifies,
this is the one you have to perform.  If laws and regulations
mandated accounting in 16th of a currency unit, you'd have to
consider that amount as 1/16th, i.e. 0.625 -- "erring" the other
way.  In neither case would it be acceptable to carry around the
"exact" amount and then say, for example, to a customer who owns
1000 units of the stock, that he must pay a charge of 6.168209
dollars or euros (not even if you rounded it to 6.17 _at this
stage_) -- in one case you would overcharging by 16.8209 (or 17
cents), in the other, undercharging by 8 cents wrt the 6.25 the
tax authorities will later want.

I realize worrying about these 8 or 17 cents _seems_ silly, but, 
it IS what accountants *DO* -- and if one writes accounting
software one should really play by their rules (or be Microsoft,
who feels free to have "rules" in VB and [different ones, I'm
told] Excel arithmetic which drive accountants batty:-).

Note that the operation that gives trouble here is not a
division -- it's a multiplication.  The problem is with carrying
around "unbounded precision" _when laws and regulations
tell you otherwise_.  Forcing the user to remember to round
again (by calling the appropriate rounding function) after every
multiplication is dangerous, because subtly wrong but plausible
results will come if the user forgets one of those calls.  The
sensible approach would seem to be to imbue every Decimal instance
with the rounding rules that instance is supposed to follow (in
most programs the rules will be the same for every instance, but
_allowing_, albeit with some trouble if need be, particularly
complicated programs to carry on computations with several
different sets of rules, would be good -- as long as no accidental
and incorrect "mix" of them can happen by mistake).


There may be use cases where "unbounded precision" is the rule
that an application needs and yet ease of division is not needed.

I'm not sure there are any easy examples (e.g., in a purely
indicative "what if" scenario it might be cool to keep unbounded
precision if performance allowed -- although in that case I
suspect "error-bounds propagation" might be even more useful --
but for such [not-necessarily-quick-but]-dirty computations, the
inability to just divide with / would be a bit cumbersome) but
surely there may be some (it's up to advocates of your variant
of "unbounded precision" to come up with real use cases for them,
of course).  But the bread-and-butter use cases for computations
with money don't require unbounded precision and in fact may be
worse off with it when it conflicts with laws and regulations --
specified precision rules per Decimal instance looks therefore like
a vastly preferable solution, and the special case of unbounded
precision may be handled either by allowing "unbounded precision"
as one of the special precision/rounding rules sets, or making a
specialcase 'unboundeddecimal' type, perhaps a subclass of the
ordinary bounded-precision decimal type, if implementation turns
out to be simpler that way.

> need to specify the result number of decimal places and the rounding
> policy. Every other operation has a well defined result that won't
> ever lead to repeating decimal representations, etc.

No, but repeating decimals are not the only problem; and the rules
of unbounded precision are not the only ones in town, so the "well
defined result" they produce need not be the same as the "well
defined result" produced by other rules which laws or regulations
(more often than not based on specified finite precision) mandate.


> My basic suggestion for that is to replace the division operators
> with a div() function that lets you specify the number of places
> and the rounding policy.

I have no issue with that, but I definitely think that, to actually
be USEFUL in practice, Decimal instances should be able to carry
around their own precision and rounding-rules.  Then you can use
explicit div and mul (functions or methods) when you want to 
explicitly specify something different -- probably add and sub too,
when you want to produce a Decimal that may have different rules
as a result, or explicitly "mix" (operate betweem) instances that
might have different and possibly conflicting rules.  But you can
also use the ordinary operators in ordinary circumstances when you
are operating between instances that have the same rules.  In
this case, I think that add(a,b) , mul(a,b) , etc, without specific
parameters for precision, rounding, nor other rules, might be
totally equivalent to a+b , a*b , etc.  It costs nothing and it
might endear us a little bit to the "migrating from Cobol" crowd
(OK, not as much as "add a to b" would, but we can't have that:-).


Alex





More information about the Python-list mailing list