-1

My question was labeled as a duplicate of https://stackoverflow.com/a/22023918/856090 but it is not a duplicate. That question covers the case of inexact representation, while this my question is about exact representation in a special case

In a Python 3 session:

>>> 0.1*3/3
0.10000000000000002
>>> 12.34567
12.34567

The first calculation produces a non-exact result. (I do understand why: it is because floating point numbers are rounded.)

But the second calculation (switching from a decimal fraction to a binary FP and then back) produces an exact result.

My question is why the second result (and many similar "calculations" involving only one FP number without arithmetic operations) is exact (the same as typed in the Python session)?

Also: What's about exactness of a sum of two decimal fractions (whose exponents don't differ much)?

Community
  • 1
  • 1
porton
  • 5,214
  • 11
  • 47
  • 95
  • Possible duplicate of [Why Are Floating Point Numbers Inaccurate?](http://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – Matt Clark Mar 15 '17 at 20:33
  • 1
    A question that has been asked and answered many times before; this is an issue with floating point math in general, and is language agnostic. – Matt Clark Mar 15 '17 at 20:33
  • @MattClark You've misread my question! I ask about the case of **exact** representation when switching from/to a decimal number, not about **inexact** representation as answered in these questions you refer me to – porton Mar 15 '17 at 20:39
  • 1
    Your question does not make sense to me. What do you mean by `switching from a decimal fraction to a binary floating point and back`? You loose your accuracy with your first decimal multiplication. – Matt Clark Mar 15 '17 at 20:47
  • 2
    Mostly duplicate of http://stackoverflow.com/a/39012152/856090 – porton Mar 15 '17 at 20:50
  • @MattClark I am about the second calculation (converting `12.34567` to binary FP and back to decimal), not about the first one (`0.1*3/3`) – porton Mar 15 '17 at 20:51
  • What _calculation_ are you referring to? There is enough precision to accurately represent, with precision, `12.34567`. If you enter `>>> 12.3456777777777777` you will see `12.345677777777778`. – Matt Clark Mar 15 '17 at 20:53
  • @MattClark I refer to converting `12.34567` to binary FP and back to decimal – porton Mar 15 '17 at 20:55
  • 1
    Possible duplicate of [Conversion of decimal floating point numbers to binary and back](http://stackoverflow.com/questions/39011905/conversion-of-decimal-floating-point-numbers-to-binary-and-back) – John Kugelman Mar 16 '17 at 14:07

3 Answers3

5

It's not "exact"... 12.34567 does not have an exact representation as a binary64. But Python's default rules for float-to-string conversion produce the same as the input you fed in. If you were to force it to give you the whole story, it would reveal the inexactness:

>>> '{:.500}'.format(12.34567)
'12.3456700000000001438138497178442776203155517578125'
Sneftel
  • 40,271
  • 12
  • 71
  • 104
0

There are two limitations on exact representation.

The first one, which eliminates numbers such as 12.34567 and 0.1, is that it must have a finite representation as a radix 2 fraction. It must be equal to A/B where A is an integer and B is an integer power of two, such as 1, 2, 4, 8, etc.

This can be tested fairly easily. First write the number as a ratio. For example, 0.1 is 1/10. Reduce to its lowest terms. 1 and 10 have no common integer factors other than 1, so 1/10 is already reduced. Look at the denominator, 10. It is not a power of 2, so 0.1 is not exactly representable.

Now consider 0.375. It is equal to 375/1000, or 3/8. 8 is a power of two, so 0.375 has a finite binary fraction representation.

The second set of conditions limit the sizes of the numbers involved to fit in the specific floating point format.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • This answers the title, but not this: "My question is why the second result is exact (the same as typed in the Python session)?" – John Kugelman Mar 16 '17 at 02:01
  • 1
    @JohnKugelman It is not possible to explain why the second result is exact, because it isn't. As pointed out in the prior answer, inexactness is being hidden by the default float-to-string conversion precision. – Patricia Shanahan Mar 16 '17 at 02:25
  • That should be in your answer. – John Kugelman Mar 16 '17 at 02:50
  • @JohnKugelman Why? The false assumption that an arbitrary example was exact had already been handled. I was either going to post on the broader issue of how to determine exactness, or not post at all. Merely repeating the previous answer would be pointless. – Patricia Shanahan Mar 16 '17 at 14:03
0

You cannot do base 10 things and assume they work in base 2 the same way.

Double precision IEEE

0.1 = 0x3FB999999999999A
3.0 = 0x4008000000000000
12.34567 = 0x4028B0FBA8826AA9
0.1*3.0 = 0x3FD3333333333334
(0.1*3.0)/3.0 = 0x3FB999999999999B

single is easier to deal with on a calculator, and notice the interesting difference:

0.1 = 0x3DCCCCCD
3.0 = 0x40400000
12.34567 = 0x414587DD
0.1*3.0 = 0x3E99999A
(0.1*3.0)/3.0 = 0x3DCCCCCD

so first off

0x3DCCCCCD is 0 01111011 10011001100110011001101

Notice the repeating pattern just like in base ten if we have a three in the denominator 1/3 = 0.3333333. And like 1/6 0.16666667 because we rounded up. Well look one bit past the end it would have been 1001 at the end but that is one bit too many, if the number after the point you are going to chop off is greater than half you round up right so 0.1001 rounds to 0.101 in binary yes? same deal here.

In this case for your decimal numbers single precision came up with the right answer multiply some number by three then divide it again and you get the same number, but in double the rounding clips at a different point, we rounded up again and ended up with a number that was very slightly larger than started.

This can all be very easily seen in decimal. If my format is a fixed number of digits I have to stop at some point so 1/6 = 0.166666 lets say or it is 0.166667. and 6.0 is lets say 6.00000. So if I use my decimal floating point format and multiply 6 * (1/6) I get either 0.99996 or 1.000002 in neither case to I get 1. Not because of rounding but because the number cannot be accurately represented in that format.

If you get back the number you started with when you go from some base 10 ASCII string to float then back to some base 10 ASCII string, then that is just luck. Either the number was accurately represented in floating point or it wasnt. You can see with the very simple base 10 floating point above that no matter how many digits you have shy of infinity, you will not get 6 * (1/6) = 1, because base 10 float cannot accurately represent 1/6th in a fixed number of digits.

Looking at your other number

12.34567 = 0x414587DD
0 10000010 10001011000011111011101
12.34567 = 0x4028B0FBA8826AA9
0 10000000010 1000101100001111101110101000100000100110101010101001

1.10001011000011111011101
1.1000101100001111101110101000100000100110101010101001

Clearly single does not have enough bits to represent it, and there wasnt a round up as the next bit was a zero which is less than half. And the double keeps working numbers to the end, I am not going to hand convert this back to base 10, but am willing to bet you just got lucky. If you were to have many more bits would that settle down or not? Again I am not going to hand convert that for you. I think you should be able to see that even if you just looked at 0.1 and went to float and back to ASCII you dont get 0.1 back. Just like in base ten 1/6th doesnt convert there and back, if you round it you would get lucky: 5.9999... rounds to 6.0 if you clip/round it at the right place, but that is just rounding for the ASCII conversion and not the actual number represented by the floating point format.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • and yes this topic has been covered countless times, the linked questions are most likely duplicates...or this is a duplicate of those that is. – old_timer Mar 16 '17 at 03:00
  • when does floating point round exactly? between the last digit in the mantissa and the sticky bit off the end of that mantissa before it is clipped, exactly like base 10 in grade school. Round to N digits. The number of digits is well documented, wikipedia has nice pictures. – old_timer Mar 16 '17 at 03:03