Question:
The Java compiler produces incorrect floating point results. It has a bug, right?
goodman38
2009-03-24 20:19:10 UTC
Several days ago, I asked the following question at the Java Forum community:

Under Windows XP, a Java program that multiplies the number 3.4 three times (such as 3.4*3.4*3.4) produces a product of 39.303999999999995 instead of the correct 39.304. This means that the JDK has a bug, doesn’t it? Can I get the correct result?

The answer I got is this:
"Certainly not. See: http://docs.sun.com/source/806-3568/ncg_goldberg.html

Define ‘correct’. It’s floating-point, not decimal. You can get whatever number of decimal digits and rounding you like with DecimalFormat or java.math.BigDecimal."


I completely disagree with that answer. Reason: all calculators show a product of 39.304; a C++ program shows 39.304; even when I do it by hand, I get 39.304. The only thing that doesn’t show 39.304 is the Java program. 3.4x3.4x3.4 doesn’t require any rounding at all—you get a clear cut number of 39.304. In science, we try to be as accurate as possible. What is your opinion?
Three answers:
videobobkart
2009-03-24 20:48:38 UTC
You may want to read the link he replied with for a better explanation.



Numbers in programming languages are represented in binary (generally). There are some that can use decimal (Cobol for example), but they are the exception. In binary, only multiples of positive or negative powers of two can be added, subtracted, or multiplied without having to resort to rounding. An example in decimal is 1/3, it can't be completely accurately represented in base 10. In binary, 1/5 (for example) has the same problem, but can be represented fine in base 10 (0.2), so even though you can perform some calculation involving a few digits to the right of the decimal point in base 10 completely accurately, that does not mean that it can also be done in base 2 without inaccuracies creeping in along the lines of the 1/3 problem in decimal. The calculator that you are using that comes up with the right answer may well be using base 10 to perform the calculations. The C++/etc. examples you give might be rounding to fewer digits (try double in C++) to achieve the right answer, but both Java and C++ use binary to represent numbers. Oh and the "problem" is not in the JDK, arithmetic operations are built into Java (and C++), JDK is a library of types (classes, interfaces, etc.) and how multiplication works in Java is not defined there.



There are classes that support "arbitrary precision" and even decimal-based arithmetic operations (note java.math.BigDecimal in the reply from Sun). And you can easily write them yourself. But no matter what base you choose (2 or 10 or something else) there will still be the problem of some fractional number not being precisely representable using that base. The next level up from there would be rational numbers, and there are classes for that too, that get around the base problem by always representing any fraction as a ratio of two whole numbers. These are also easy to write.
plavacek
2009-03-24 22:33:16 UTC
You can get the correct result. The problem is that you declared your numbers as "double". Declare them as float instead and you'll get the correct output _in this case_.



float fl = 3.4f * 3.4f * 3.4f;

System.out.println(fl);



I think if you declare the value as double in C++, you'll get the same mysterious output. The calculator probably does the math in float, and your way of doing math by hand is different from the computer's way.



That link they sent you to is a good one, but the concept is a little obtuse, so let me try to explain.



Computers don't think in decimal. They think in binary. So all numbers eventually have to be represented in binary. Likewise, Java's Virtual Machine thinks in binary.



Well, the decimal side of a number almost never has a "clean" binary representation. .1 is the most famous example - in binary, it's a repeating fraction.



So there's two problems with fractional multiplication in programs - first, storing the decimal number, and second, multiplying them. Just like the storage, the multiplication has to be done in binary. The result then has to be converted into base 10 to show you. What the runtime will try to do is to figure out if there's a better, more rounded, cleaner answer. In double though, that automatic rounding point is a long ways down, and your example causes it to trip.



Float uses less precision, and different storage, so in this case at least it works out - the extra precision is rounded out during the operation or conversion. In Java, double is the default, whereas in C variants, I think float is(?). Hence you getting a different answer in C++.
?
2016-04-07 05:25:31 UTC
Michelle: The first link is to some guy who is a patent creationist, and not a scientist. Some of the links from there were good, but only in one case did they actually mention anything about carbon dating being wrong. And it was simply a case of misuse, on marine fossils. The third link is about labs which preform radiocarbon dating and their accuracy, not inaccuracies in the actual method itself. Problems with the labs. And your second link is still based on the technology and research done in the 1970s. I'm not sure how accurate that is currently. So you have yet to give anything but lab mistakes and dated research. Please try again.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...