decimal or rational (was Re: Against PEP 240)

Don O'Donnell donod at home.com
Fri Jun 1 18:49:08 EDT 2001


Alex Martelli wrote:
> 
>"Laura Creighton" <lac at cd.chalmers.se> wrote in message
>news:mailman.991303187.29241.python-list at python.org...
>    ...
> > <And thanks to more conversation with Remco Gerlich I think that it
> > is decimal, not rational that is the way to go, somebody try to talk us
> > out of it>  is exactly what Burke was talking about.
>
> I'm not a candidate for "talking (anybody) out of it", where
> "it" is having (e.g.) 7.35 mean a floating-point-decimal 7.35
> rather than a rational 7.35, because I'm _deeply_ undecided
> myself.  My criterion: what *WOULD* be harder to explain to (and
> have accepted by) an intelligent beginner?  Potentially *VERY
> SLOW* (and memory-consuming) behavior for computation, or the
> risk of unexpected (to said beginner) 'strange' results?  And
> I'm not talking about a vacuum -- I'm talking about a real-world
> where people's expectations ARE very much shaped by the
> calculators they've dealt with for years, and those ARE FP
> decimal (at least typically).  A computation doesn't slow
> down as it proceeds, but it does often lose precision...

If by "floating-point-decimal" you mean internal representation of
both the mantissa and the exponent by some sort of a binary-coded 
decimal, let me point out that it is not necessary to go to full 
decimal in order to to achieve the `7.35` == "7.35" goal.

By letting the exponent represent powers of 10 rather than 2, the 
base or mantissa can be represented in binary as an int or long.
Thus, the internal calculations can use the fast integer hardware
instructions, rather than decimal arithmetic which would have 
to be done by software.

Scaling would require a multiply or divide by 10 every time the
exponent is incremented/decremented by one, not as fast as a
left or right bit shift; but it can be done pretty fast considering
that a multiply by 10 is equivalent to a left shift by 3 (*8)
followed by two adds (10*x == (8+2)*x == 8*x + 2*x == 8*x + x + x):

>>> x = 42
>>> (x<<3) + x + x    # multiply by 10 without using * op
420

I'm not sure that this is any faster than x*10; in Python, probably
not, but in C it may be. (Haven't looked at any CPU timing charts 
lately, so I may be all wet here; it used to be that mult & div were 
very expensive.)  (A quick timing check shows that 
the above shift and add calculation takes about 3 times longer in
Python than a straight *10, as expected.)

Obviously, this binary-based decimal-powered floating-point would 
not be as fast as using the hardware FPU, but it wouldn't be as bad as 
doing all calculations in decimal as with a full decimal implementation.

I'm in the process of writing an "efloat" class which implements 
these ideas as a proof of concept.  "efloat" for expected float, 
i.e., one that meets your expectations, no surprises, as with:

>>> 7.35
7.3499999999999996

If someone can think of a better name please let me know.
I didn't want to call it dfloat since that should be reserved for
a full decimal implementation.  Come to think of it, efloat may 
not be such a good name since it can be confused with the "e"
in the binary float literal display (0.735e1).

I'll post the source code when I'm done, in case anyone is interested
in checking it out.

As far as decimal vs rational for a built-in Python type, couldn't
we have both?  And if we do get both, I think: 

7.35   or   735d-2    should be the literal for the decimal-float
7.35e0  or  735e-2    should be the literal for binary float
735/100  or 735r-2    should be the literal for rationals

-Don



More information about the Python-list mailing list