[Tutor] Need a better name for this function

Dave Angel davea at ieee.org
Wed Dec 16 04:32:10 CET 2009

Richard D. Moores wrote:
> On Tue, Dec 15, 2009 at 15:05, Dave Angel <davea at ieee.org> wrote:
>> Richard D. Moores wrote:
> If I keep the function, renamed to Allan's suggested float2Decimal(),
> then that's all I'll have to remember. But I see yours and Hugo's
> point.
Just remember, if the entire body of the function is just a call to the 
other one, all you need is an assignment.  It'll go faster, too.  So 
whatever you decide to call it, you just need something like:
   float2Decimal = decimal.Decimal.from_float
>> As for the name being too long, the real question is what's the purpose of the function.
> I don't know if it will be useful or not, but it will satisfy my
> curiosity, given a float, as to what the "exact number stored in my
> computer is".
But it doesn't do that.  I'll try to elaborate below.
>>  It certainly doesn't give you an exact representation, as that cannot be done in general, without changing the defaults in the decimal module.  For example, try 2.0 ** -50    The exact decimal version of that needs 50 digits, and Python 3.1 docs say it uses 28 by default..
> For (2.0 ** -50) I get 8.8817841970012523233890533447265625E-16, or 35
> digits. But for an ordinary 1.341 I get
> 1.3409999999999999698019337301957421004772186279296875 -- 53 digits.
> Dave, I just realized that you used the term, "exact representation".
> What does that mean? If it means "exact decimal version", what does
> THAT mean? I'm not being facetious. I'm truly confused by this stuff
> -- "the exact number stored in my computer" is the first phrase I've
> understood. With 2.x I was totally in the dark about repr().
> Dick
Don't be misled by repr().  It's not even intended to give you an exact 
representation, only to get one that can be used to reproduce the binary 
fp value you happen to have.  And the success at doing that has varied 
from version to version of CPython.

My background:   In 1975 I implemented a decimal floating point system 
for a proprietary machine architecture.  I started by implementing add 
and subtract, and ended up with logs, and trig.  I was at that time very 
familiar with the tradeoffs of binary and decimal floating point.

Float in most Python implementations is implemented in terms of the IEEE 
standard (754?) for binary floating point.  On most (?) machines these 
days, there is direct microcode support for such numbers.  For example, 
in the Pentium, the instruction set deals directly with them.  Even back 
to the Intel 8088, there was in the early 80's an 8087 aux chip that 
provided this floating point.  At one time I was quite familiar with 
most of the details, though I may not have them all perfect right now.

A binary fp number takes up 64 bits, of which some 53 represent the 
mantissa, and most of the rest are the exponent.  There are a bunch of 
tricky things, such as the sticky bit and gradual underflow, as well as 
a few NAN values, and some infinities.  But most numbers can be 
understood if you have a good knowledge of both base 10 and base 2 

Conversely, the Decimal package is a decimal system, implemented as 
variable precision, and a variable number of bytes.  I tried in about 
1984 convince the IEEE committee to include decimal fp at that time, but 
since their main goal was codifying the 8087 chip, they declined.  There 
were other reasons as well, one of which is that a decimal number format 
doesn't fit as efficiently into memory.  But IEEE did have another, 
later standard (854?) that was radix-independent, and variable 
precision.  I think Python's Decimal package implements that standard, 
which isn't accelerated significantly by any processor I'm familiar with.

So Decimal takes more space, and runs slower..   So why bother?  Because 
it can represent exactly numbers the way human beings deal with them, 
and can do roundoff in familiar ways, and avoid quantization effects in 
confusing places.  It's perfect for accounting type applications.  Not 
only that, but converting back and forth to decimal strings need not 
introduce any more errors.

For integers of reasonable sizes, the two are interchangeable.  But for 
fractional values each has different characteristics.  Take the number 
1/3.  Try to represent it in decimal, and it takes an infinite number of 
digits to get exact representation.  So we use some elipses notation, 
and nobody minds too much.  But the computer is more literal, and you 
have to be careful.  If you take 0.3333333 and multiply by 3, you do not 
get 1.0.   You get 0.9999999    Maybe you can round it, and maybe you 
can't.  But a decimal package will have the same issues as a hand 
calculation.  A binary system cannot represent 1/3 either.  But it'll 
get a different error, and be off by a different amount.  And by the 
time you get done converting to decimal for printout., the problem may 
be masked, or it may be made worse.

But what about 1/10 ?  In a decimal package you can represent that 
precisely, with just a few digits of precision.  In binary fp, it is not 
exact.  and if you have that number stored it'll be off a little bit.  
Converting it to decimal to print it out may make the error vanish, or 
it may make it worse.  So applications do some rounding, before 
converting to printable form or after, or both.  If you know your binary 
value is correct to 50 bits or so, and you round to 14 digits, it'll 
seem to be always accurate for nice values like 1/10.  But a 14 digit 
decimal representation is not an exact representation of the binary value.

To exactly represent a binary value with a 53 bit mantissa would take 53 
decimal digits, worst case.  Would they all have meaning in a realistic 
calculation?  Nope.  But when you say exact representation, that's what 
you'd need.

(disclaimer:  the 53 bits is a long-term memory, and is likely off by a 
couple.  And other calculations could be plus or minus 1 or 2.  I'm just 
writing this quickly.  So maybe you'd need 54 decimal digits, or whatever.)


More information about the Tutor mailing list