BigDecimal для bignumber не работает правильно в значении с плавающей запятой
E сть BigDecimal
Тип данных в Java. Когда я объявляю число 5190000000 как BigDecimal следующим образом:
BigDecimal a = new BigDecimal(5190000000L * 1.0F);
, он взволнован и виден следующий результат:
Output:
5190000128
в то время как я опускаю F как значение с плавающей точкой, это правильно, как это:
BigDecimal a = new BigDecimal(5190000000L * 1.0);
Output:
5190000000
Что это? и как параметр F допускает ошибку? Я действительно запутался!!!!
РЕДАКТИРОВАТЬ
Версия JDK составляет 1,8
4 ответа
Перед BigDecimal
построено, выражение внутри скобок должно быть оценено в первую очередь.
Так, 5190000000 * 1.0F
оценивается в float
значение, но это значение не совсем 5190000000. Почему? Потому что 5190000000 не может быть точно представлен в float
, Некоторая точность уже потеряна до того, как BigDecimal
создано. Поэтому вывод, который вы видите, не является точным.
Во втором случае 5190000000 * 1.0
оценивается в double
, а также double
имеет достаточную точность, чтобы точно представлять 5190000000. Почему это оценивается в double
на этот раз?, спросите вы. Так как 1.0F
является литералом с плавающей точкой, и 1.0
это двойной литерал. И это решает тип выражения.
Чтобы получить точное значение, используйте строковый конструктор:
BigDecimal bd = new BigDecimal("5190000000");
bd = bd.multiply(BigDecimal.ONE); // if you insist on multiplying it by 1
Это ожидаемое поведение. Выражение 5190000000 * 1.0F
оценивается как число с плавающей точкой, точность которого составляет от 6 до 7 десятичных цифр.
На самом деле, значение, которое вы в конечном итоге получите, является точным до 7 цифр.
Вы никогда не должны создавать BigDecimal
с использованием double
конструктор. Как double
(или же float
(в данном случае), который вы передаете, неточно для начала, эта неточность будет отражена в BigDecimal
,
Рекомендуется либо использовать String
или же long
конструкторы для BigDecimal
, или valueOf
фабричный метод, чтобы инициализировать BigDecimal
, поскольку они с большей вероятностью сохранят необходимую вам точность.
причина- метод построения BigDecimal, тип параметра двойной. - Итак, ваш первый код будет сделан неявным преобразованием компилятором, что создаст некоторую проблему потери точности. - Но ваш второй код '1.0', тип по умолчанию - double, так что это правильно. - Другое дело, что для типа int максимальное значение равно 2147483647, ваш заданный параметр - 5190000000, что приведет к ошибке компиляции.