Вопрос-ответ

How to resolve a Java Rounding Double issue [duplicate]

Как решить проблему двойного округления Java

Похоже, что вычитание вызывает какую-то проблему, и результирующее значение неверно.

double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;

78.75 = 787.5 * 10.0 / 100d

double netToCompany = targetPremium.doubleValue() - tempCommission;

708.75 = 787.5 - 78.75

double dCommission = request.getPremium().doubleValue() - netToCompany;

877.8499999999999 = 1586.6 - 708.75

Результирующее ожидаемое значение будет равно 877,85.

Что следует сделать, чтобы обеспечить правильное вычисление?

Переведено автоматически
Ответ 1

Для контроля точности арифметики с плавающей запятой вам следует использовать java.math.BigDecimal. Прочитайте О необходимости BigDecimal Джона Жуковски для получения дополнительной информации.

Учитывая ваш пример, последняя строка будет следующей с использованием BigDecimal .

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf("1586.6");
BigDecimal netToCompany = BigDecimal.valueOf("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

Это приводит к следующему результату.

877.85 = 1586.6 - 708.75
Ответ 2

Как указывалось в предыдущих ответах, это следствие выполнения арифметики с плавающей запятой.

Как предлагалось в предыдущем постере, при выполнении числовых вычислений используйте java.math.BigDecimal.

Однако в использовании есть ошибка BigDecimal. При преобразовании значения double в a BigDecimal у вас есть выбор: использовать новый BigDecimal(double) конструктор или BigDecimal.valueOf(double) статический заводской метод. Используйте статический заводской метод.

Конструктор double преобразует всю точность double в a BigDecimal, в то время как статическая фабрика эффективно преобразует ее в a String, а затем преобразует это в a BigDecimal.

Это становится актуальным, когда вы сталкиваетесь с этими незначительными ошибками округления. Число может отображаться как .585, но внутренне его значение равно '0.58499999999999996447286321199499070644378662109375'. Если бы вы использовали BigDecimal конструктор, вы бы получили число, КОТОРОЕ НЕ равно 0.585, в то время как статический метод выдал бы вам значение, равное 0.585.

двойное значение = 0,585;
System.out.println(новый BigDecimal(значение));
System.out.println(BigDecimal.valueOf(значение));

в моей системе выдает

0.58499999999999996447286321199499070644378662109375
0.585
Ответ 3

Another example:

double d = 0;
for (int i = 1; i <= 10; i++) {
d += 0.1;
}
System.out.println(d); // prints 0.9999999999999999 not 1.0

Use BigDecimal instead.

EDIT:

Also, just to point out this isn't a 'Java' rounding issue. Other languages exhibit
similar (though not necessarily consistent) behaviour. Java at least guarantees consistent behaviour in this regard.

Ответ 4

I would modify the example above as follows:

import java.math.BigDecimal;

BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

This way you avoid the pitfalls of using string to begin with.
Another alternative:

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

I think these options are better than using doubles. In webapps numbers start out as strings anyways.

java