Исправлена ​​ошибка точности поплавка без BigDecimal

У меня проблема с округлением значения с плавающей запятой.

Следующий код дает мне следующий результат:

public class ProductOrder {

  public static void main(String[] args) {
    int q = 48;
    float p = 6.95f;

    System.out.println(q * p);
  }

------
Output: 333.59998

Пока ожидаемый результат должен быть 333,6

Когда я заменяю q на 49, тогда все в порядке, и я получаю 340,55

4 ответа

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

Второе лучшее решение - это, например, работать с целым числом центов и вставлять десятичную точку только во время отображения.

Если вы должны использовать двоичную с плавающей запятой, обычно лучше использовать double, чем float, если только вы не имеете дело с большим числом чисел и знаете, что у float достаточно точности.

Для вывода, если вы ожидаете результат с, например, не более 2 десятичными цифрами после десятичной точки, вы можете использовать DecimalFormat для округления соответственно:

import java.text.DecimalFormat;

public class Test {
  public static void main(String[] args) {
    DecimalFormat df = new DecimalFormat("#0.##");
    int q = 48;
    float p = 6.95f;
    System.out.println(df.format(q * p));
  }
}

печатает 333.6

Форматирование по умолчанию производит наименьшее количество цифр, которое необходимо, чтобы отличить число от соседей. Это означает, что если результат даже слегка отклонен из-за ошибки округления, вы получите "некрасивый" вывод.

Один из способов справиться с этим - использовать точную арифметику (BigDecimal или целочисленную арифметику). Другой округляет вывод, например:

System.out.printf("%f", p*q);

Число 333.6 не представляется точно так же, как float, который имеет точность до 6 десятичных цифр. Когда вы пытались напечатать его с слишком большой точностью (8 цифр), была обнаружена основная ошибка округления.

double имеет точность до 15 цифр.

Однако, как отмечали другие, если вы имеете дело с финансовыми расчетами, вы должны работать в BigDecimal,

Для справки вы можете использовать веб-сайт IEEE-754 для преобразования с плавающей запятой, чтобы увидеть, для любого заданного десятичного числа, как именно оно представлено в float а также double,

Проблема здесь заключается в том, что числа с плавающей запятой подвержены ошибкам точности с плавающей запятой. Ты можешь использовать double для удвоения точности (вы все равно в конечном итоге получите ошибки, но это более точно, чем использование float).

Например

public static void main(String[] args) {
    int q = 48;
    double p = 6.95;

    System.out.println(q * p);
}

Это даст 333,6.

Другие вопросы по тегам