When a double
value is printed, Java uses the return value of Double.toString(double)
, which says:
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.
So, lets print the values of 0.1 - 1.0, and their adjacent values. We use Math.nextDown(double)
and Math.nextUp(double)
to find the adjacent values. We use new BigDecimal(double)
and toPlainString()
to see more digits from the value.
We also calculate the value from summing multiple 0.1
values and mark that value with a <
, =
, or >
, as appropriate.
System.out.printf("%9s%-13s%-12s%s%n", "", "double", "sum", "BigDecimal");
double sum = 0.1;
for (int i = 1; i <= 10; i++, sum += 0.1) {
double val = i / 10d;
double down = Math.nextDown(val);
double up = Math.nextUp(val);
System.out.printf("%d:%n %-21s%-3s%s%n %-21s%-3s%s%n %-21s%-3s%s%n",
i,
down, (sum == down ? "<" : " "), new BigDecimal(down).toPlainString(),
val, (sum == val ? "=" : " "), new BigDecimal(val).toPlainString(),
up, (sum == up ? ">" : " "), new BigDecimal(up).toPlainString());
}
Output
double sum BigDecimal
1:
0.09999999999999999 0.09999999999999999167332731531132594682276248931884765625
0.1 = 0.1000000000000000055511151231257827021181583404541015625
0.10000000000000002 0.10000000000000001942890293094023945741355419158935546875
2:
0.19999999999999998 0.1999999999999999833466546306226518936455249786376953125
0.2 = 0.200000000000000011102230246251565404236316680908203125
0.20000000000000004 0.2000000000000000388578058618804789148271083831787109375
3:
0.29999999999999993 0.29999999999999993338661852249060757458209991455078125
0.3 0.299999999999999988897769753748434595763683319091796875
0.30000000000000004 > 0.3000000000000000444089209850062616169452667236328125
4:
0.39999999999999997 0.399999999999999966693309261245303787291049957275390625
0.4 = 0.40000000000000002220446049250313080847263336181640625
0.4000000000000001 0.400000000000000077715611723760957829654216766357421875
5:
0.49999999999999994 0.499999999999999944488848768742172978818416595458984375
0.5 = 0.5
0.5000000000000001 0.50000000000000011102230246251565404236316680908203125
6:
0.5999999999999999 0.5999999999999998667732370449812151491641998291015625
0.6 = 0.59999999999999997779553950749686919152736663818359375
0.6000000000000001 0.600000000000000088817841970012523233890533447265625
7:
0.6999999999999998 0.69999999999999984456877655247808434069156646728515625
0.7 = 0.6999999999999999555910790149937383830547332763671875
0.7000000000000001 0.70000000000000006661338147750939242541790008544921875
8:
0.7999999999999999 < 0.79999999999999993338661852249060757458209991455078125
0.8 0.8000000000000000444089209850062616169452667236328125
0.8000000000000002 0.80000000000000015543122344752191565930843353271484375
9:
0.8999999999999999 < 0.899999999999999911182158029987476766109466552734375
0.9 0.90000000000000002220446049250313080847263336181640625
0.9000000000000001 0.9000000000000001332267629550187848508358001708984375
10:
0.9999999999999999 < 0.99999999999999988897769753748434595763683319091796875
1.0 1
1.0000000000000002 1.0000000000000002220446049250313080847263336181640625
As you can see, because of cumulative rounding issues, the summed value is not always exactly the value closest to what you'd expect, so it has to print extra digits for that "unique" value.
The summed value is wrong for 0.3
, 0.8
, 0.9
, and 1.0
.