Проблема с округлением Java - PullRequest
       28

Проблема с округлением Java

3 голосов
/ 28 декабря 2011

По сути, я не понимаю, почему приведенный ниже код будет выводить 434, когда 4,35 * 100 = 435,0, который преобразуется в целое число 435, верно?

Каково простое объяснение этого и является ли этопроблема, которая возникает часто?

Как бы вы обойти это?

public class RoundOffDemo {
    public static void main(String[] args) {
        double price = 4.35;
        int cents = (int) (100 * price); // Should be 435
        System.out.println(cents); // Prints 434!
    }
}

Ответы [ 6 ]

7 голосов
/ 28 декабря 2011

Проблема в том, что 4.35 нельзя точно представить в двоичном виде. Так что 4.35 * 100 это не совсем 435.0. (Каждая дробь в двоичном виде представляет собой сумму обратных степеней 2, все из которых заканчиваются десятичными знаками. К сожалению, десятичная дробь 0,35 имеет неразрывное двоичное расширение. Поэтому 4.35 больше похоже на 4,349999 ... x (где x - это нечто, за пределами которого все равно нулю, благодаря конечному представлению машины чисел с плавающей запятой.) В результате целочисленного усечения получается 434. Вы можете использовать Math.round(), чтобы избежать этой проблемы.

2 голосов
/ 28 декабря 2011

IMO, предложения по использованию BigDecimal излишни.Для центов используйте длинный.Даже государственный долг США может быть покрыт с использованием длинных центов.

Если вы используете числа с плавающей запятой (или двойные), при преобразовании в целые числа используйте Math.round (), Math.floor () или Math.ceil () в зависимости от ситуации.

0 голосов
/ 28 декабря 2011

Двойное значение 4.35 фактически представлено как 4.349999999999999.100 * 4,349999999999999 = 434,999999999999.А приведение его к значению int даст вам 434.

0 голосов
/ 28 декабря 2011

если вы используете этот код:

System.out.println(price*100); // Prints 434!

вы заметите, что его вывод равен

434.99999999999994

, округленный до 434

0 голосов
/ 28 декабря 2011

Это результат арифметики с плавающей запятой.(int) приведение не является функцией округления, а скорее усечением, как указывает @Ted.

Поскольку вы имеете дело с деньгами (как видно из имен ваших переменных), используйте вместо этого BigDecimal.

Например -

double d = 4.35;
BigDecimal bd = BigDecimal.valueOf(d);
bd  = bd.multiply(new BigDecimal(100));
0 голосов
/ 28 декабря 2011
  1. Не используйте double / float для арифметики с плавающей точкой в ​​Java, вместо этого используйте BigDecimal.Это связано с тем, что Java не может точно представить число с плавающей точкой.

  2. Всегда используйте BigDecimal для временных переменных, которые будут обрабатываться / участвовать в будущих вычислениях.Преобразуйте значения в плавающие / двойные, только если вы хотите сохранить их в базе данных.

...