Richard D. Moores wrote:
On Tue, Dec 15, 2009 at 15:05, Dave Angel <[email protected]> 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

_______________________________________________
Tutor maillist  -  [email protected]
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to