Inverse confusion about floating point precision

S

Skip Montanaro

I understand why the repr() of float("95.895") is "95.894999999999996".
What I don't understand is why if I multiply the best approximation to
95.895 that the machine has by 10000 I magically seem to get the lost
precision back. To wit:

% python
Python 2.3.4 (#12, Jul 2 2004, 09:48:10)
[GCC 3.3.2] on sunos5
Type "help", "copyright", "credits" or "license" for more information. 958950.0

Why isn't the last result "958949.99999999996"? IOW, how'd I get back the
lost bits?

Thx,

Skip
 
D

Dan Bishop

Skip said:
I understand why the repr() of float("95.895") is "95.894999999999996".
What I don't understand is why if I multiply the best approximation to
95.895 that the machine has by 10000 I magically seem to get the lost
precision back. To wit:

% python
Python 2.3.4 (#12, Jul 2 2004, 09:48:10)
[GCC 3.3.2] on sunos5
Type "help", "copyright", "credits" or "license" for more information.958950.0

Why isn't the last result "958949.99999999996"? IOW, how'd I get back the
lost bits?

You were just lucky.

The floating-point representation of 95.895 is exactly 6748010722917089
* 2**-46.

Multiplying by 10000 gives you 67480107229170890000 * 2**-46. But
floats can have only 53 significant bits, so this gets normalized to
8237317776998399.658203125 * 2**-33 and rounded to 8237317776998400 *
2**-33, which happens to be exactly equal to 958950.

For analogy, consider a decimal calculator with only 3 significant
digits. On this calculator, 1/7=0.143, an error of 1/7000.
Multiplying 0.143 by 7 gives 1.001, which is rounded to 1.00, and so
you get an exact answer for 1/7*7 despite roundoff error in the
intermediate step.
 
S

Skip Montanaro

Why isn't the last result "958949.99999999996"? IOW, how'd I get
Dan> You were just lucky.

Thanks for the response (and to Tim as well).

Dan> The floating-point representation of 95.895 is exactly
Dan> 6748010722917089 * 2**-46.

I seem to recall seeing some way to extract/calculate fp representation from
Python but can't find it now. I didn't see anything obvious in the
distribution.

Thx,

Skip
 
T

Tim Peters

[Dan]
Dan> The floating-point representation of 95.895 is exactly
Dan> 6748010722917089 * 2**-46.

[Skip Montanaro]
I seem to recall seeing some way to extract/calculate fp representation from
Python but can't find it now. I didn't see anything obvious in the
distribution.

For Dan's example,
import math
math.frexp(95.895) (0.74917968749999997, 7)
int(math.ldexp(_[0], 53))
6748010722917089L
 
B

Bengt Richter

Skip said:
I understand why the repr() of float("95.895") is "95.894999999999996".
What I don't understand is why if I multiply the best approximation to
95.895 that the machine has by 10000 I magically seem to get the lost
precision back. To wit:

% python
Python 2.3.4 (#12, Jul 2 2004, 09:48:10)
[GCC 3.3.2] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
95.894999999999996
95.895 * 10000
958950.0

Why isn't the last result "958949.99999999996"? IOW, how'd I get back the
lost bits?

You were just lucky.

The floating-point representation of 95.895 is exactly 6748010722917089
* 2**-46.

Multiplying by 10000 gives you 67480107229170890000 * 2**-46. But
floats can have only 53 significant bits, so this gets normalized to
8237317776998399.658203125 * 2**-33 and rounded to 8237317776998400 *
2**-33, which happens to be exactly equal to 958950.

For analogy, consider a decimal calculator with only 3 significant
digits. On this calculator, 1/7=0.143, an error of 1/7000.
Multiplying 0.143 by 7 gives 1.001, which is rounded to 1.00, and so
you get an exact answer for 1/7*7 despite roundoff error in the
intermediate step.

In bits, the above appears as
>>> prb(95.895) '1011111.1110010100011110101110000101000111101011100001'
>>> len(prb(95.895).split('.')[1]) 46
>>> prb(95.895*2**46) '10111111110010100011110101110000101000111101011100001'
>>> int(prb(95.895*2**46),2) 6748010722917089L
>>> int(prb(95.895*2**46),2)*10000 67480107229170890000L
>>> prb(int(prb(95.895*2**46),2)*10000) '111010100001111001011111111111111111111111111111111111010100010000'
>>> prb(int(prb(95.895*2**46),2)*10000)[:53] '11101010000111100101111111111111111111111111111111111'
>>> int(prb(int(prb(95.895*2**46),2)*10000),2)/2.**46 958950.0
>>> prb(int(prb(int(prb(95.895*2**46),2)*10000),2)/2.**46)
'11101010000111100110'

Regards,
Bengt Richter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top