It's not particularly well-explained by the documentation, but Double.toString(double)
essentially performs some rounding in the output it produces. The Double.toString
algorithm is used all throughout Java SE, including e.g. PrintStream.println(double)
of System.out
. The documentation says this:
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
.
In other words, it says that the return value of toString
is not necessarily the exact decimal representation of the argument. The only guarantee is that (roughly speaking) the argument is closer to the return value than any other double
value.
So when you do something like System.out.println(1.10)
and 1.10
is printed, this does not mean the value passed in is actually equivalent to the base 10 value 1.10
. Rather, essentially the following happens:
- First, during compilation, the literal
1.10
is examined and rounded to produce the nearest double
value. (It says in the JLS here the rules for this are e.g. detailed in Double.valueOf(String)
for double
.)
- Second, when the program runs,
Double.toString
produces a String
representation of some decimal value which the double
value produced in the previous step is closer to than any other double
value.
It just so happens that conversion to String
in the second step often produces a String
which is the same as the literal in the first step. I'd assume this is by design. Anyhow though, the literal e.g. 1.10
does not produce a double
value which is exactly equal to 1.10
.
You can discover the actual value of a double
(or float
, because they can always fit in a double
) using the BigDecimal(double)
constructor:
When a double
must be used as a source for a BigDecimal
, note that this constructor provides an exact conversion; it does not give the same result as converting the double
to a String
using the Double.toString(double)
method and then using the BigDecimal(String)
constructor. To get that result, use the static
valueOf(double)
method.
// 0.899999999999999911182158029987476766109466552734375
System.out.println(new BigDecimal((double) ( 2.00 - 1.10 )));
// 0.89999997615814208984375
System.out.println(new BigDecimal((float) ( 2.00 - 1.10 )));
You can see that neither result is actually 0.9
. It's more or less just a coincidence that Float.toString
happens to produce 0.9
in that case and Double.toString
does not.
As a side note, (double) (2.00 - 1.10)
is a redundant cast. 2.00
and 1.10
are already double
literals so the result of evaluating the expression is already double
. Also, to subtract float
, you need to cast both operands like (float) 2.00 - (float) 1.10
or use float
literals like 2.00f - 1.10f
. (float) (2.00 - 1.10)
only casts the result to float
.