Java BigDecimal разница - PullRequest
       8

Java BigDecimal разница

2 голосов
/ 16 мая 2011

Я хотел бы узнать, может ли кто-нибудь объяснить, почему следующий код работает со значениемOf, а не с другими.

import java.math.BigDecimal; 
public class Change {
   public static void main(String args[]) {
     double a = 4.00d;
     double b = 3.10d;
     BigDecimal a1 = new BigDecimal(a);
     BigDecimal b1 = new BigDecimal(b);
     BigDecimal diff = a1.subtract(b1);
     System.out.println("Double difference");
     System.out.println(diff);

     float c = 4.00f;
     float d = 3.10f;
     BigDecimal a2 = new BigDecimal(c);
     BigDecimal b2 = new BigDecimal(d);
     BigDecimal diff2 = a2.subtract(b2);
     System.out.println("Float difference");
     System.out.println(diff2);

     System.out.println("Valueof Difference");
     System.out.println(BigDecimal.valueOf(4.00).subtract(BigDecimal.valueOf(3.10)));

   }
 }

Вывод выглядит так:

>java Change
 Double difference
  0.899999999999999911182158029987476766109466552734375
 Float difference
  0.900000095367431640625
 Valueof Difference
 0.9

Мой вопрос: чтоvalueOf () делает, чтобы получить точность?Есть ли другой способ получить правильный результат без округления до 2 цифр вручную?

спасибо,

Ответы [ 4 ]

8 голосов
/ 16 мая 2011

Глядя на исходный код для BigDecimal, он делает:

public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory approach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}

Из своего JavaDoc:

Преобразует двойное в BigDecimal, используя предоставленное представление канонической строки двойногометодом Double.toString (double).

Примечание. Как правило, это предпочтительный способ преобразования double (или числа с плавающей запятой) в BigDecimal, поскольку возвращаемое значение равно значению, полученному в результате создания BigDecimal из результата использования Double.toString (double).

Из-за представления с плавающей запятой двойное значение не совсем то, что вы задали.Однако во время представления String он округляет то, что отображает.(Все правила указаны на JavaDoc ).

Более того, из-за этого округления вы сделали:

BigDecimal d = BigDecimal.valueOf(4.00000000000000000000000000000000001));

васполучит неправильное значение.(d == 4.0)

Итак, всегда лучше инициализировать их строками.

1 голос
/ 16 мая 2011

Из Javadocs :

public static BigDecimal valueOf(double val)

переводит двойное в BigDecimal, используя каноническую строку двойника представительство предоставляется Метод Double.toString (double). Замечания: Как правило, это предпочтительный способ конвертировать двойной (или плавающий) в BigDecimal, поскольку возвращаемое значение равна тому, что в результате построение BigDecimal из результат использования Double.toString (двойной).

Я думаю, что это отвечает на оба ваших вопроса.

Приветствия

1 голос
/ 16 мая 2011

BigDecimal.valueOf(double) сначала выполняет преобразование из double в String, затем String в BigDecimal.

В первом случае вы начинаете с double или float, конвертируясь в BigDecimal, вычисляя разницу. Во втором случае вы начинаете с double или float, конвертируясь в String, , затем , конвертируя в BigDecimal, затем вычисляя разницу.

1 голос
/ 16 мая 2011

Значение valueOf работает, потому что оно вызывает Double.toString. из Javadoc:

public static BigDecimal valueOf(double val)

    Translates a double into a BigDecimal, using the double's

каноническое строковое представление предоставлено Метод Double.toString (double).

Когда вы передаете double в конструктор BigDecimal, конструктор принимает значение с плавающей запятой и точно его воспроизводит. Код toString находит аппроксимацию для значения с плавающей запятой.

Если вы не заметили, использование System.out.println () для отображения числа с плавающей запятой не дает таких же результатов, как если бы вы сначала оборачивали число с плавающей запятой в BigDecimal (используя конструктор BigDecimal, который занимает двойной).

...