Java Doubles are not good at math [closed]

2020-02-06 18:25发布

问题:

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 8 years ago.

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

回答1:

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.



回答2:

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 next double 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 decimal 12.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 a Formatter (in java.util).



回答3:

I have noticed that doubles in java are not at all like doubles in c++.

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 that BigDecimal arithmetic is many orders of magnitude slower than floating point, and the APIs are more cumbersome to use.



回答4:

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)



回答5:

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.



回答6:

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.