-1

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

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
The Dude
  • 310
  • 7
  • 15
  • 5
    Really, you are very likely to run into the same problems in C++. It is not a problem with java but how IEEE doubles work. If it happens to work for you in C++ you are mostly lucky. Read the section "IEEE 754: floating point in modern computers" of http://en.wikipedia.org/wiki/Floating_point. Maybe what you're missing is just a formatting of output but that doesn't solve the problems you will run into unless you understand the reason why you get 12.29999999999 and not 12.3 in the first place. – Fredrik Mar 21 '11 at 22:47
  • 1
    I know in C++ you can set the precision of double outputs. I'm sure there's something you can do in Java. – Chance Mar 21 '11 at 22:47
  • 6
    What Every Computer Scientist Should Know About Floating Point Arithmetic http://cr.yp.to/2005-590/goldberg.pdf – epatel Mar 21 '11 at 23:12
  • possible duplicate of [Strange floating-point behaviour in a Java program](http://stackoverflow.com/questions/327544/strange-floating-point-behaviour-in-a-java-program) – jk. Mar 22 '11 at 08:05

6 Answers6

8

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.

geekosaur
  • 59,309
  • 11
  • 123
  • 114
7

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).

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
5

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++ does1, 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.


1 - I have recently learned that this may incorrect. In fact some C++ compilers are known to use 80-bit "extended" floating point when evaluating (some) expressions. Unfortunately, the precise behavior is not specified, and this means that floating point codes written in C++ can give different results depending on the compiler vendor, compilation options and so on.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

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)

bestsss
  • 11,796
  • 3
  • 53
  • 63
1

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.

biziclop
  • 48,926
  • 12
  • 77
  • 104
0

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.

user unknown
  • 35,537
  • 11
  • 75
  • 121