При выполнении двойных операций необходимо обеспечить соответствующее округление.Даже для деления BigDecimal необходимо обеспечить соответствующее округление.
Для печати double
выполняется небольшое количество округления, чтобы вы не увидели ошибку представления.Однако, после нескольких вычислений (требуется только один), ошибка округления слишком велика, и вы можете увидеть ошибку.
Если вы хотите увидеть ошибку представления и округления, используйте BigDecimal, поскольку он выполняет точное преобразование издвойной.Что-то, что само по себе может удивить.
Кстати, вы не получите ошибку округления с простыми степенями 2. поэтому -9,5 + 2,5 + 7,0 всегда будет 0,0.Вы получите ошибку округления только с другими десятичными знаками, такими как 0,1
double[] ds = {
0.1,
0.2,
-0.3,
0.1 + 0.2 - 0.3};
for (double d : ds) {
System.out.println(d + " => " + new BigDecimal(d));
}
prints
0.1 => 0.1000000000000000055511151231257827021181583404541015625
0.2 => 0.200000000000000011102230246251565404236316680908203125
-0.3 => -0.299999999999999988897769753748434595763683319091796875
5.551115123125783E-17 => 5.5511151231257827021181583404541015625E-17
Вы можете видеть, что представление для 0,1 и 0,2 немного выше этих значений, и -0,3 этотакже немного выше.Когда вы печатаете их, вы получите более приятное значение 0,1 вместо фактического значения, представленного 0,1000000000000000055511151231257827021181583404541015625
Однако, когда вы добавляете эти значения вместе, вы получаете значение, немного превышающее 0.
КомуЧтобы решить эту проблему, необходимо обеспечить соответствующее округление.С деньгами это легко, поскольку вы знаете, сколько десятичных разрядов уместно, и если у вас нет $ 70 триллионов, вы не получите достаточно большую ошибку округления, вы не сможете ее исправить.
public static double roundToTwoPlaces(double d) {
return ((long) (d < 0 ? d * 100 - 0.5 : d * 100 + 0.5)) / 100.0;
}
Если вы добавите это вВ результате все еще существует небольшая ошибка представления, однако она недостаточно велика, чтобы Double.toString (d) не могла исправить ее.
double[] ds = {
0.1,
0.2,
-0.3,
0.1 + 0.2 - 0.3};
for (double d : ds) {
System.out.println(d + " to two places " + roundToTwoPlaces(d) + " => " + new BigDecimal(roundToTwoPlaces(d)));
}
print
0.1 to two places 0.1 => 0.1000000000000000055511151231257827021181583404541015625
0.2 to two places 0.2 => 0.200000000000000011102230246251565404236316680908203125
-0.3 to two places -0.3 => -0.299999999999999988897769753748434595763683319091796875
5.551115123125783E-17 to two places 0.0 => 0