Rational Numbers

Nick Maclaren nmm1 at cus.cam.ac.uk
Sat Jan 13 05:40:22 EST 2007


In article <mailman.2666.1168632007.32031.python-list at python.org>,
"Simon Brunning" <simon at brunningonline.net> writes:
|> >
|> > Financial calculations need decimal FIXED-point, with a precisely
|> > specified precision.  It is claimed that decimal FLOATING-point
|> > helps with providing that, but that claim is extremely dubious.
|> > I can explain the problem in as much detail as you want, but would
|> > very much rather not.
|> 
|> Sorry, Nick, you might have to. ;-)
|> 
|> I'm not educated in these matters, so I'd genuinely like to know why
|> you say that. Not educated, but I do have some experience; I've used
|> both fixed and floating point Decimal types extensively, and I've
|> found floating types superior. More fiddly, certainly, 'cos you have
|> to explicitly round back down to the precision that you want when you
|> want. But explicit is better than implicit - the number of subtle
|> rounding bugs that I've had to fix 'cos someone didn't realise where
|> rounding was occurring is, uh, well, it happens from time to time. ;-)
|> 
|> What am I missing?

I will try to give a simple explanation, but I need to gloss over a
hell of a lot.  The precision is the number of digits after the
decimal point.

Financial calculations are defined in terms of decimal fixed-point,
with precisely specified precisions and rounding rules (though both
may vary with context, even in one expression).  Now, let's ignore
the arcana (especially as I know only a little of them) and note only
the following:

The traditional way of implementing fixed-point is as scaled integers,
and this is easy and reliable.  It is tricky if the USER is expected
to do it, but it is trivial to excapsulate.  Hell, even PLAN (the ICL
1900 assembler) did it!

If a number is calculated in floating-point, decimal or otherwise, and
needs any rounding, then it will NOT follow the right rules and no
reasonable amount of post-operation munging will enable it to do so.
Fixing up double rounding problems is inherently foul, so it is
ESSENTIAL that no operation is approximate.

In true fixed-point, the result of multiplication has a precision that
is the sum of the input precisions, and addition, subtraction and
remainder the maximum of the two.  Division is required to specify a
target precision and rounding rule.  Overflow is raised when the total
number of digits exceeds the space available.

A typical financial multiplication is a monetary amount multiplied by
a rate (say VAT, interest or a conversion rate).  That typically has
up to 5 digits, but there is no reason that it can't be more, and
it is possible that some calculations multiply several rates together.

When emulated in floating-point, the exception raised when the number
of digits exceeds the space available is Inexact (there is a slightly
different one for decimal, but the differences don't matter here).  So,
to get correct fixed-point flag handling, Inexact must be mapped to
Overflow.

Except for division, where there is no way to use the floating-point
primitive as a basis for the fixed-point one, so it has to be done by
hand, tediously and slowly.

But, in scientific (and current Python) usage, Inexact is always ignored
and Overflow is almost always an error.  If we do that mapping, it will
break ALL scientific code.  But, if we DON'T do that mapping, we will
abandon any attempt at getting reliable fixed-point overflow detection.
So you can't mix the two in the same program - which was one of the
main objectives of using decimal floating-point!

The counter-argument is that everyone will use 128-bit arithmetic for
all purposes.  Well, that is hooey, because it will cause MAJOR problems
for both the embedded people (logic, power and performance) and HPC
people (performance, mainly bandwidth).  Python could, probably.

However, that isn't what the Decimal module does anyway.  People will
specify more digits than they possibly need, not realising that they
need to specify many MORE if they are going to support multiplication.

Coming back to the start, is fixing that little lot up REALLY easier
than encapsulating scaled integers to give a proper fixed-point type?
I think that you will find that it is much harder!


Regards,
Nick Maclaren.



More information about the Python-list mailing list