views:

67

answers:

3

i do the below java print command for this double variable double test=58.15; When i do a System.out.println(test); and System.out.println(new Double(test).toString()); It prints as 58.15.

When i do a System.out.println(new BigDecimal(test)) I get the below value 58.14999999999999857891452847979962825775146484375

I am able to understand "test" double variable value is internally stored as 58.1499999. But when i do the below two System.out.println i am getting the output as 58.15 and not 58.1499999.

System.out.println(test);

System.out.println(new Double(test).toString());

It prints the output as 58.15 for the above two.

Is the above System.out.println statements are doing some rounding of the value 58.1499999 and printing it as 58.15?

+4  A: 
System.out.println(new BigDecimal("58.15"));

To construct a BigDecimal from a hard-coded constant, you must always use one of constants in the class (ZERO, ONE, or TEN) or one of the string constructors. The reason is that one you put the value in a double, you've already lost precision that can never be regained.

EDIT: polygenelubricants is right. Specifically, you're using Double.toString or equivalent. To quote from there:

How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.

Matthew Flaschen
Thanks a lot for the info
Arav
+3  A: 

Yes, println (or more precisely, Double.toString) rounds. For proof, System.out.println(.1D); prints 0.1, which is impossible to represent in binary.

Also, when using BigDecimal, don't use the double constructor, because that would attempt to precisely represent an imprecise value. Use the String constructor instead.

polygenelubricants
I am assuming new BigDecimal("52.15") or double test=52.15;new BigDecimal(new Double(test).toString()) are one and the same. Pls correct me if i am wrong. My understanding is new Double( double variable).toString takes the rounded value 58.15 and not 58.149999999. Does it do any rounding? So the results are same if i use either way?
Arav
@arav: No they are not the same. The string constructor does not loose precision but the double one already has lost it. That is, the double is already 58.149999 when you call the constructor. Also, it does not do any rounding, it uses the raw bits to construct exactly what you give it.
Kevin Brock
Yes, `Double.toString(.1D).equals("0.1")`, and yes, rounding did occur here. `.1D` is not exactly `0.1`, but `Double.toString` rounds to it. This is a "two wrongs make it right" kind of scenario which you should not rely on.
polygenelubricants
Opps, yes I misread that comment and mixed up with what you were saying in your answer and then OP. In the OP the issue is that he is using a double directly in the BigDecimal constructor and that is the problem.
Kevin Brock
poly, so your saying it will give me the same output if i use new BigDecimal(Double.toString(doublevariable)) instead of Bigdecimal("52.15"). if its going to give me the same output then it's a workaround right? In what cases this might fail?
Arav
`Double.toString(1.0000000000000001D).equals("1.0")`, precision is lost due to rounding.
polygenelubricants
+1  A: 

out.println and Double.toString() use the format specified in Double.toString(double).

BigDecimal uses more precision by default, as described in the javadoc, and when you call toString() it outputs all of the characters up to the precision level available to a primitive double since .15 does not have an exact binary representation.

Yishai
Thanks a lot for the info
Arav