7

I happened upon these values in my ColdFusion code but the Google calculator seems to have the same "bug" where the difference is non-zero.

416582.2850 - 411476.8100 - 5105.475 = -2.36468622461E-011

http://www.google.com/search?hl=en&rlz=1C1GGLS_enUS340US340&q=416582.2850+-+411476.8100+-+5105.475&aq=f&oq=&aqi=

JavaCast'ing these to long/float/double doesn't help- it results in other non-zero differences.

ale
  • 6,369
  • 7
  • 55
  • 65
Brian Pan
  • 144
  • 1
  • 8
  • 17
    There should be a floating point quiz when creating an account on SO. I think this is the most commonly asked question on the site. – recursive Jan 04 '10 at 22:48
  • 3
    @recursive: http://meta.stackexchange.com/questions/26621/whats-the-most-repeated-question-on-stackoverflow/26633#26633 – Michael Myers Jan 04 '10 at 22:49
  • 1
    When I learned to program, the lack of precision in floating point numbers was mentioned the very first time floating point was discussed, and several times thereafter. Don't they do that any more? – Paul Tomblin Jan 04 '10 at 22:50
  • Heh, same bug in Haskell and its usually quite good at these things: Prelude> 416582.2850 - 411476.8100 - 5105.475 -2.3646862246096134e-11 – Jamie McCrindle Jan 04 '10 at 22:51
  • 3
    -2.36468622461E-011? In my neighborhood, he answers to "zero". – President James K. Polk Jan 04 '10 at 22:54
  • I remember when one of our junior developers got tripped up by floating point precision for the first time. *sniffle* They grow up so fast! – Dana Jan 04 '10 at 22:55

7 Answers7

17

This is because decimal numbers that "look" round in base 10, are not exactly representable in base 2 (which is what computers use to represent floating point numbers). Please see the article What Every Computer Scientist Should Know About Floating-Point Arithmetic for a detailed explanation of this problem and workarounds.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 1
    5105.475 was the number that wasn't representable exactly in a double. PrecisionEvaluate is the ColdFusion function I needed. – Brian Pan Jan 04 '10 at 23:23
  • Actually, none of those numbers are exactly representable as double precision values. – Stephen Canon Jan 04 '10 at 23:31
  • +1 excellent reference, also check out "How to Print Floating-Point Numbers Accurately" by G.L. Steele – D.Shawley Jan 04 '10 at 23:58
  • 1
    I read this paragraph this morning, I swear: "If I could go back in time and change one thing, I might try to interest some early preliterate people in not using their thumbs when they count. It could have been the standard, and it would have made a whole lot of things easier in the modern era. On the other hand, we have learned a lot from the struggle with the incompatibility of base-ten with powers of two." -Guy Steele, Coders At Work – Brian Pan Jan 05 '10 at 00:50
  • While base 8 might be convenient for computers, I would suggest that if we all had six fingers on each hand (base 12) then our number system would have been better overall. 12 has more small factors than 10. – Greg Hewgill Jan 05 '10 at 01:28
7

Floating-point inaccuracies (there are an infinite number of real numbers and only a finite number of 32- or 64-bit numbers to represent them with).

If you can't handle tiny errors, you should use BigDecimal instead.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
  • But 416582.2850 - 411476.8100 can be represented *exactly* as 5105.475. These are numbers with only 4 decimals, not repeating. Is 4 decimals too precise? – Brian Pan Jan 04 '10 at 22:57
  • 2
    It's not the base-10 representation that has to be finite, it's the base-2 representation. See http://en.wikipedia.org/wiki/Binary_numeral_system#Fractions_in_binary for an explanation of which fractions can be represented exactly in binary (it's only those which have 2 as a prime factor of the denominator). – Michael Myers Jan 04 '10 at 23:10
  • @Brian: It's not the number of decimals. The fraction 1/3 can't be represented in base 10, right? It would be 3.3333333 repeating. The same goes for decimals (or fractions) in binary (base 2). 1.1, although valid in base 10, cannot be accurately represented in base 2, and thus results in what you could call a "rounding error". – Sasha Chedygov Jan 04 '10 at 23:11
6

Use PrecisionEvaluate() in ColdFusion (it'll use BigDecimal in Java)

zero = PrecisionEvaluate(416582.2850 - 411476.8100 - 5105.475);

unlike Evaulate(), no "" is needed.

Henry
  • 32,689
  • 19
  • 120
  • 221
2

Since computer stores numbers in binary, float numbers are imprecise. 1E-11 is a tiny difference due to rounding these decimal numbers to the nearest representable binary number.

yu_sha
  • 4,290
  • 22
  • 19
2

This "bug" is not a bug. It's how floating point arithmetic works. See: http://docs.sun.com/source/806-3568/ncg_goldberg.html

If you want arbitrary precision in Java, use BigDecimal:

    BigDecimal a = new BigDecimal("416582.2850");
    BigDecimal b = new BigDecimal("411476.8100");
    BigDecimal c = new BigDecimal("5105.475");
    System.out.println(a.subtract(b).subtract(c)); // 0.0
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
1

The problem is the inexact representation of floating point types. Because these can't be exactly represented as floats, you get some precision loss that results in operations have small errors. Typically with floats you want to compare whether the result is equal to another value within some small epislon (error factor).

tvanfosson
  • 524,688
  • 99
  • 697
  • 795
1

These are floating point issues and using BigDecimal will fix it.

Changing the order of subtraction also yields zero in Google.

416582.2850 - 5105.475 - 411476.8100 = 0
danielrsmith
  • 4,050
  • 3
  • 26
  • 32