[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:
<snip>
> 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
arithmetic.
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.)
HTH
DaveA
More information about the Tutor
mailing list