The cause of the problem
Your problem is further down. For example, look at this:
public class Main {
public static void main(String[] args) {
double a = 10000999999999999999100.69d;
double b = 10001000000000000000000d;
System.out.println(a);
System.out.println(a == b);
}
}
Here’s the way out:
1.0001E22
true
See here this running on ideone.
What happens is that your number has been rounded up to be stored in the double
. In your case, the double
is not accurate enough to store your number (see more here). The greater the magnitude of the number, the less accurate the double
. The double
has a 52-bit precision. Which means that numbers that need more than 52 bits to be stored will somehow be rounded.
To know exactly how yours double
is being stored, we can do this:
public class Main {
public static void main(String[] args) {
double a = 10000999999999999999100.69d;
String x = Long.toBinaryString(Double.doubleToRawLongBits(a));
while (x.length() < 64) {
x = "0" + x;
}
System.out.println(x);
}
}
Here’s the way out:
0100010010000000111100010011111000001100000000110111001011001101
See here this running on the ideone.
What this pattern means?
0
- Positive number.
10001001000
- Exponent. That is 8 + 64 + 1024 = 1096. There is a 1023 bias (one must subtract 1023), and therefore the exponent is 1096 - 1023 = 73.
0000111100010011111000001100000000110111001011001101
- The fraction is 265,248,791,818,957
- I mean, this is:
(1 + (265.248.791.818.957 / 252)) * 273
273 + (265.248.791.818.957 / 252) * 273
273 + (265.248.791.818.957 / 252) * 252 * 221
273 + 265.248.791.818.957 * 221
273 + 265.248.791.818.957 * 2.097.152
9.444.732.965.739.290.427.392 + 556.267.034.260.709.310.464
10.000.999.999.999.999.737.856
Okay, the final number represented is 10,000,999,999,999,999,737,856. So why was 10,001,000,000,000,000,000? The answer is because, as you can see, there was loss of precision in the stored number. Therefore, considering that there was this loss, there are several different numbers that will be presented as if they were equal. And then, the algorithm that shows the double
as a string, it seeks to produce in the string, the value that has the roundest decimal representation among the possible numbers that will produce it, and not the representation of the exact nominal value.
What are these various numbers that will generate this representation? We can add 1 the fraction up there and redo the calculation to find the next representable value, which is 10,001,000,000,000,001,835,008. The difference is 2,097,152 = 273-52 = 221. This also shows that by the great magnitude of the number, the accuracy of the double
for this range of numbers is already so small that the difference between two distinguishable values is 2,097,152.
Whereas numbers can be rounded up or down and the nominal value is the centre of the range of values it represents, thus the margin of error for each side is 1,048,576 from the nominal value (1,048,576 = 2,097,152 / 2). There is also a preference for the number with the even fraction in case the number is equidistant between two representable points. With that, we have to all values x
such that 10.000.999.999.998.689.280 < x < 10.001.000.000.000.786.432 are represented in the same way in a double
and therefore indistinguishable. Of these, the number 10,001,000,000,000,000,000 is the one with the round decimal representation. And its number 10,000,999,999,999,999,999,100.69 is within this range.
How to solve
Just wear the class BigDecimal
. Abandon the double
if you want arbitrary accuracy. Also use class DecimalFormatSumbols
along with the DecimalFormat
. Here’s the code:
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
var formatter = new DecimalFormat("#,###.##");
var s = new DecimalFormatSymbols();
s.setDecimalSeparator(',');
s.setGroupingSeparator('.');
formatter.setDecimalFormatSymbols(s);
var numero = new BigDecimal("10000999999999999999100.69");
System.out.println(formatter.format(numero));
}
}
Here’s the way out:
10.000.999.999.999.999.999.100,69
See here working on ideone.