Ошибка BigDecimal - PullRequest
       65

Ошибка BigDecimal

5 голосов
/ 17 января 2012

В Java я определил k как double k=0.0;

Я беру данные из базы данных и добавляю их, используя цикл while,

while(rst.next()) {
k = k + Double.parseDouble(rst.getString(5));
}

NOTE: In database, I have values as 125.23, 458.45, 665.99 (all two decimals)

Когда я отображаю k, я получаю значение как

k = 6034.299999999992

Поэтому я ввел BigDecimal и изменил код ниже

      BigDecimal bd = new BigDecimal(k);
      bd = bd.setScale(2,BigDecimal.ROUND_UP);

Теперь я получаю новый итог как bd=6034.30, что правильно.

Задача 1

Ну, проблема в том, когда я использую то же самое в другом месте, ниже то, что я получаю

 k  = 157.3
 bd = 157.31

Он должен был показать bd=157.30, так как после добавления вручную я получаю 157.30.

Любая причина, по которой он отображается как 157.31.

Задача 2

Также есть какая-то причина, почему k показывает так много десятичных значений? Ниже приведены различные значения, которые я получаю для двойной переменной k

157.3
67.09
1014.6000000000003
229.06999999999996

Я не понимаю, что иногда он отображает один десятичный знак, иногда он отображает 2 десятичных знака и большую часть времени показывает 14 десятичных значений.

Любое предложение будет оценено.

Ответы [ 5 ]

7 голосов
/ 17 января 2012

Вы все еще едете через double.Придерживайтесь BigDecimal везде :

BigDecimal k = BigDecimal.ZERO;
while (rst.next()) {
    k = k.add(new BigDecimal(rst.getString(5));
}

Альтернативно и предпочтительно, если поле в базе данных фактически является десятичным значением:

BigDecimal k = BigDecimal.ZERO;
while (rst.next()) {
    k = k.add(rst.getBigDecimal(5));
}
6 голосов
/ 17 января 2012

Что касается вашего второго вопроса, double - это двоичное число с плавающей запятой .Это означает, что оно выражается как сумма степеней двух. Никогда не используйте их для расчета денежных величин. (если вы там и подводите итоги).BigDecimal использует десятичную арифметику, так что это больше соответствует тому, что мы используем.

Числа, такие как 0.1, представляют собой бесконечные дроби в двоичном виде, в данном случае: 0.000110011..., таким образом, вы не можетеполучить надежный и точный результат от использования double.

3 голосов
/ 17 января 2012

Полагаю, rst - это ResultSet.Убедитесь, что вы используете getBigDecimal вместо Double.parseDouble(rst.getString(5)):

BigDecimal k = BigDecimal.ZERO;
while(rst.next()) {
  k = k.add(rst.getBigDecimal(5));
}

И прежде всего: почему вы не добавляете эти числа в базу данных напрямую используя соответствующий запрос SQL SUM?

2 голосов
/ 17 января 2012

Использовать BigDecimal.ROUND_HALF_UP (или .._ ВНИЗ или .._ ДАЖЕ).

Вычисления с плавающей точкой по своей сути неточны, и небольшие ошибки накапливаются. Вот почему ваш конечный результат не очень хороший. Если вы всегда округляетесь, небольшая положительная ошибка, такая как 1.0000000001, становится 1.01.

В качестве альтернативы вы можете использовать BigDecimal также для расчетов. Таким образом, у вас не будет ошибки в конечном результате. Просто не забудьте использовать конструктор BigDecimal (String) или получить BigDecimal непосредственно из набора результатов.

0 голосов
/ 17 января 2012

Вам также нужно иметь k как BigDecimal вместо double.

...