8

When I type this into the Visual Studio 2008 immediate window:

? .9 - .8999999999999995

It gives me this as the answer:

0.00000000000000055511151231257827

The documentation says that a double has 15-16 digits of precision, but it's giving me a result with 32 digits of precision. Where is all that extra precision coming from?

H H
  • 263,252
  • 30
  • 330
  • 514
raven
  • 18,004
  • 16
  • 81
  • 112
  • 29
    I wonder how many questions related to floating point precision problems we have on SO. – Mehrdad Afshari Nov 02 '09 at 17:48
  • 5
    @Mehrdad: Way too many. It's such a simple thing: base 10 != base 2. Yet, everyone feels compelled to treat it like it's the Most Amazing Thing Ever! – S.Lott Nov 02 '09 at 18:07
  • 5
    People, please read, this is about why the answer uses 32 digits. Not about not being exact. – H H Nov 02 '09 at 18:07
  • 2
    Henk, please comprehend, that's not how floating point works. – Jimbo Nov 02 '09 at 18:25
  • 2
    Henk, I think this question could have been phrased better. If OP had even mentioned in the beginning of the question that he/she knew about FP precision, then it probably would have stopped all of the FP answers. – Jim Deville Nov 02 '09 at 18:38
  • @Mehrdad's comment makes me wonder how many distinct floating point precision problems are possible. – Bill the Lizard Nov 02 '09 at 20:30
  • 5
    @Mehrdad: I write a script to count it, and there are 201.00000001918371 such questions. not sure how I counted a fractional question though, maybe I'll post a question with my source code to ask for an explanation. – toasteroven Nov 02 '09 at 20:31

6 Answers6

41

There are only 15-16 digits in the answer. All those leading zeroes don't count. The number is actually more like 5.5511151231257827 × 10-16. The mantissa portion has 15-16 digits in it. The exponent (-16) serves to shift the decimal point over by 16 places, but doesn't change the number of digits in the overall number.

Edit

After getting some comments, I'm curious now about what's really going on. I plugged the number in question into this IEEE-754 Converter. It took the liberty of rounding the last "27" into "30", but I don't think that changes the results.

The converter breaks down the number into its three binary parts:

Sign: 0 (positive)
Exponent: -51
Significand: 1.0100000000000000000000000000000000000000000000000000 (binary for 1.2510)

So this number is 1.012 × 2-51, or 1.2510 × 2-51. Since there are only three significant binary digits being stored, that would suggest that Lars may be onto something. They can't be "random noise" since they are the same each time the number is converted.

The data suggests that the only stored digit is "5". The leading zeros come from the exponent and the rest of the seemingly-random digits are from computing 2-51.

Barry Brown
  • 20,233
  • 15
  • 69
  • 105
  • Where are all those other digits being stored? – Barry Brown Nov 03 '09 at 06:31
  • Not, it is the decimal representation of a binary point number. Including it's rounding errors. – Dykam Nov 03 '09 at 06:34
  • 3
    Wrong: "Leading zeroes don't count" is incorrect. The 15-16 important digits in the answer are 0.0000000000000005. The digits after that are incorrect, and are only present because the rounding errors are promoted into the mantissa because of the leading zeroes. As Barry wrote himself in his edit, the result is stored as 1.25*2^(-51)=5.551*10^(-16), which is a number that has 1 decimal digit of calculation accuracy, but is has 15-16 digits of storage precision. – Lars D Nov 03 '09 at 08:54
  • A more interesting behavior appears with `Convert.ToSingle("9111111.4999999990")` and `convert.ToSingle("9111111.4999999991")`. Both values are closer to 9111111 than to 9111112, but the latter one rounds up. – supercat Oct 26 '12 at 23:29
17

You should read: What Every Computer Scientist Should Know About Floating-Point Arithmetic .

Basically it comes down to Floating Point numbers being stored with finite precision. You have to do your comparison with some delta.

if(.9 - .8999999999999995 <= 0.0001)
  //close enough to be equal
Lolindrath
  • 2,101
  • 14
  • 20
  • 9
    +1: It is a shame that SO cannot auto-answer with this for each and every floating point question, being the right answer for at least 90% of floating point questions. – Richard Nov 02 '09 at 17:46
  • 2
    this doesn't address his question on precision. – Ape-inago Nov 02 '09 at 18:06
  • 5
    -1, does not answer the question. The q is about 32 digits (not 16) for a double. – H H Nov 02 '09 at 18:06
  • +1 The number of digits is not really the relevant part, it's the method of storage that this answer addresses. – StackOverflowed Oct 19 '12 at 17:34
14

The leading zeros are not significant/part of the precision (as far as the floating point number is concerned -- mathematically speaking, they are significant). The leading zeros are due to the exponent part of the floating point number's internal representation.

The portion 55511151231257827 (which is the significand or mantissa) has 17 decimal digits, which is close enough to 15-16 digits.

@Lars D: What you consider to be correct, is only correct within the context of the question. .9 - .8999999999999995 works out to a float with significand 0.625 and exponent of -50. Taking 0.625 * 2-50 results in 5.5511151231257827e-16. Now, out of the context of the original question, we have a number with 17 significant digits which does happen to be our best binary approximation of 0.0000000000000005. However, those leading zeros are still not significant as far as the representation of the floating point number is concerned.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 2
    I downvoted this answer, because I consider your answer incorrect. The 15-16 digits precision in the actual subtraction operation give 0.0000000000000005, and the rest of the digits are random rounding errors. Therefore, in the 55511151231257827 part, there is only 1 correct digit, and the rest are rounding errors, that have been promoted into the mantissa because of the leading zeroes. Basically the 32 digits are 16 significant digits from the subtraction, plus 16 digits of noise in the mantissa afterwards. The zeroes only become insignificant AFTERWARDS, when the result is stored. – Lars D Nov 03 '09 at 06:27
  • 1
    Right - if I were taking chemistry again, the leading zeros *would* be significant digits. However, the computer has no concept of whether the zeros should be significant, and that is why there are approximately 16 *non-zero* digits represented in the answer. – Mark Rushakoff Nov 03 '09 at 11:54
4

? .9 - .8999999999999995

This subtraction process, with 15-16 significant digits, gives

0.0000000000000005

The rest of the digits are just rounding errors. However, since the computer always stores 15-16 significant digits after the first non-zero digit, the rounding errors are shown, and you get a lot of trailing random digits produced by rounding errors. So the result has 16 significant digits from the subtraction operation plus 16 digits from the storage of the result, which gives 32 digits.

Lars D
  • 8,483
  • 7
  • 34
  • 37
3

The "floating" part of "floating point" means that you are getting something closer to 5.5511151231257827 * 10^(-16). That's not exactly how it's represented, because of course it's all done in binary under the hood, but the point is, the number is represented by the significant digits, plus a number which represents how far to move the radix (decimal point). As always, wikipedia can give you more detail:

(The second link is more specifically focused on your particular case.)

jcdyer
  • 18,616
  • 5
  • 42
  • 49
0

I think its because in the binary system, 5 is periodic as it is not dividable by 2. And then what Mark Rushakoff said applies.

eflorico
  • 3,589
  • 2
  • 30
  • 41