I am currently writing a calculator program in java. It is my first java program, I am used to c++.
I have noticed that doubles in java are not at all like doubles in c++.
try this in java and c++
4.1*3
that/.1
it should be
12.3 then 123, and c++ gives this result but java gives
12.299999999999999 and 122.99999999999999
How can I do math like in c++ with doubles, I understand that anything you would use 12.299999999999999 in a program at all would make no difference compared to 12.3, but when a user is reading the numbers this is very ugly. I have looked into the BigDecimal class but I cannot do trig and logarithms and whatnot with that class
The math is the same; the display is different, as most C/C++ display formats round numbers to avoid the imprecision in the least significant bits.
Did you have a look at
java.lang.StrictMath
? From the javadocs I get the impression, that it might be closer to C, but I don't do much math and can't tell for sure.Else I agree with geekosaur: Output might be the only problem,
java.text.NumberFormat
might help here.In fact, Java will be using precisely the same representation for doubles as C++ does, and the arithmetic will (most likely) be producing exactly the same values internally.
The fundamental problem here is that there is not a precise 1-to-1 mapping between binary floating point number representations and decimal representations. Numbers such as
12.3
cannot be precisely represented as binary floating numbers. It is a mathematical impossibility.To understand this (AND YOU SHOULD), read "What Every Computer Scientist Should Know About Floating-Point Arithmetic".
The difference you are observing, will be due to differences in the formatting code that turns the double values into digits for output. In the Java case, the code is giving the most accurate decimal representation of the actual double that it can achieve. In the C++ case, it is rounding off the least significant digits ... which gives the number you expect, but not the most accurate decimal representation.
Neither approach is wrong. They are just different. If you want Java to display your numbers rounded to a certain number of digits, you can do this using one of the Java formatter classes.
Another alternative is to do all of your calculator arithmetic in Java using the
BigDecimal
class. This will give you precise numbers, modulo the limitations of decimal arithmetic that you learned in high school; e.g. you can't represent fractions like 1/3 precisely in decimal. The downsides are thatBigDecimal
arithmetic is many orders of magnitude slower than floating point, and the APIs are more cumbersome to use.Every arithmetic model represents a trade-off between precision, space and speed.
Floating point, regardless of the language sacrifices some of the precision to save space and add speed.
Fixed point is a different trade-off and arbitrary precision arithmetics is yet another one.
If you want complicated calculations of arbitrary precision, you'll need a dedicated maths library like Apache commons-math or apfloat.
The Dude, Java Doubles are not good at math, they are slow but exactly as precise as Java's double (the small one) (or any other 64bit IEEE 754). BigDecimal are even slower.
(so dunno if the Dude abides)
So, why is this imprecise?:
4.1
is already not precisely representable as a binary number (no matter whether fixed- or floating point), so it is rounded to the nextdouble
value. Multiplying this by 3 does not change the fact of the non-representability, but amplifies the error so it is now a different binary value than converting from decimal12.3
would get you. Thus you get, when converting it to decimal again, the number with lots of nines.When multiplying it with 10, you simply amplify the error again by 10. (Dividing by 0.1 again introduces more error, since
0.1
is not exactly representable, too.)Your C++ program probably used exactly the same operations. The reason for the different display in Java is that it displays all digits necessary to reproduce the number from the String, while your C++ outputting function somehow rounds it. (As you show no output code, we can't be for sure what you did there.)
When outputting numbers for human users to digest, use a
NumberFormat
(in java.text) or aFormatter
(in java.util).