views:

422

answers:

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.

+7  A: 

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
Reference: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
Stefan Kendall
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
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
@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".
musicfreak
+14  A: 

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
5105.475 was the number that wasn't representable exactly in a double.PrecisionEvaluate is the ColdFusion function I needed.
Brian Pan
Actually, none of those numbers are exactly representable as double precision values.
Stephen Canon
+1 excellent reference, also check out "How to Print Floating-Point Numbers Accurately" by G.L. Steele
D.Shawley
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
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
+1  A: 

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
+1  A: 

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
+2  A: 

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
A: 

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
+5  A: 

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

zero = PrecisionEvaluate(416582.2850 - 411476.8100 - 5105.475);

unlike Evaulate(), no "" is needed.

Henry
+1 for the actual cold fusion solution
Kip