[Tutor] Need a better name for this function

Dave Angel davea at ieee.org
Wed Dec 16 11:48:23 CET 2009


Richard D. Moores wrote:
> On Tue, Dec 15, 2009 at 23:30, Hugo Arts <hugo.yoshi at gmail.com> wrote:
>   
>> On Wed, Dec 16, 2009 at 5:12 AM, Richard D. Moores <rdmoores at gmail.com> wrote:
>>     
>>> Before I can go below I need to know if you are saying that the
>>> relevant doc is wrong. I took the original name for my function almost
>>> directly from it. Near the bottom of
>>> <http://docs.python.org/3.1/tutorial/floatingpoint.html#representation-error>
>>> we find "meaning that the exact number stored in the computer is equal
>>> to the decimal value
>>> 0.1000000000000000055511151231257827021181583404541015625." And
>>> coincidence or no, that's precisely what float2Decimal() returns for
>>> 0.1 .
>>>
>>>       
>> The docs are right. The function will give you the exact value of any
>> floating point number stored in memory.
>>     
>
> OK!
>
>   
>> I think what Dave is trying to
>> say is that if you want to store the exact value 0.1 on your computer,
>> this function won't help you do that.
>>     
>
> Yes, I knew that.
>
>   
>> It also won't help you avoid any
>> kinds of rounding errors, which is worth mentioning. If you want 0.1
>> represented exactly you'll need to use the Decimal module all the way
>> and avoid floating point entirely.
>>
>> Of course, if all you want is to get a better understanding of what's
>> actually stored on your computer when you try to store 0.1 in a float,
>> this can be a useful tool.
>>     
>
> Yes, that's what I wanted the function for, and with a name that would
> be easy to remember.
>
>   
>> I also recommend the article "What Every
>> Computer Scientist Should Know About Floating-point Arithmetic." It's
>> a very detailed explanation, though somewhat technical:
>>
>> http://docs.sun.com/source/806-3568/ncg_goldberg.html
>>     
>
> I'm sleepy now, but will dig into it tomorrow.
>
> Thanks for your help, Hugo.
>
> Dick
>
>   
Hugo is right, and I was a little bit wrong.  Not about the decimal 
versus binary floating point, but about how 3.1's from_float() method 
works.  It's new in 3.1, and I didn't play with it enough.  Apparently, 
it adjusts the precision of the generated Decimal value so that it *can* 
represent the binary value exactly.  So the doc is correct that the 
representation is exact.

Note also that it takes 56 digits to do that, which is part of what I 
was trying to say.   Although I was remembering 53 bits for the mantissa 
of binary-fp, the concepts were right.  It takes about as many decimal 
digits to do it as it took for mantissa bits in the binary fp value.

If you really want to see what binary fp does, you might need to resort 
to hex.  Two methods of float are relevant, hex() and fromhex().  Check 
out the following function I just wrote.

import decimal
float2decimal = decimal.Decimal.from_float

a = 0.1
print("internal repr of 0.1 is ", a.hex())    # 0x1.999999999999ap-4


def test(stringval):
    floatval = float.fromhex(stringval)
    decimalval = float2decimal(floatval)
    print( stringval, "--", floatval, "--", decimalval )


test(" 0x1.9999999999999p-4")
test(" 0x1.999999999999ap-4")    #This is 0.1, as best as float sees it
test(" 0x1.999999999999bp-4")


The output is (re-wordwrapped for email):

internal repr of 0.1 is  0x1.999999999999ap-4
 0x1.9999999999999p-4 -- 0.1
     -- 0.09999999999999999167332731531132594682276248931884765625
 0x1.999999999999ap-4 -- 0.1
     -- 0.1000000000000000055511151231257827021181583404541015625
 0x1.999999999999bp-4 -- 0.1
     -- 0.10000000000000001942890293094023945741355419158935546875

Notice that these are the closest values to 0.1 that can be represented 
in a float, one below, and the first two above.  You can't get any 
values between those.  When you print any of them, it shows a value of 
0.1, presumably due to rounding during conversion to a decimal string.  
The algorithm used in such conversion has changed many times in the 
evolution of CPython.

And in case it's not obvious, the stringval items are 14 hex digits (56 
bits), plus the letter "p", a sign, and an exponent value.  These are 
encoded into 64bits as a float.  You can see such a value for any float 
you like, by using the method hex() on the float object.

Hugo:  thanks for the article reference.  I was pleased to see it was 
inspired by a lecture of professor Kahan.  I haven't met him in a couple 
of decades.  He was the brains behind much of Intel's 8087 
implementation, which was more-or-less used as a reference 
implementation by the IEEE standard.  And of course he was active on the 
standard.  I do recall there were a few liberties that the 8087 took 
that he wanted to be illegal in the standard, but generally it was 
assumed that the standard needed a real silicon implementation in order 
to succeed.  I wish I had a tenth of his smarts, with respect to 
floating point.

DaveA




More information about the Tutor mailing list