Странное поведение DecimalFormat с шаблоном #####0.00 в Java

Я использую привязку кода ниже, чтобы отобразить значение цены float с двумя десятичными знаками.

NumberFormat FORMAT = new DecimalFormat("#####0.00");
float myFloatValue =\\I am able to fetch this value dynamically
String finalPrice = FORMAT.format(myFloatValue);
// I am using this String (finalPrice) for export xml purpose.

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

Некоторые примеры вывода finalPrice String : 0.10999966, 0.1800003, 0.45999908.

Может ли кто-нибудь помочь мне угадать исходное значение myFloatValue из этих выходных данных? Так что это поможет мне повторить сценарий и исправить его.


person Vishal Zanzrukia    schedule 22.07.2015    source источник
comment
Каков вход для вашего примера?   -  person Jens    schedule 22.07.2015
comment
На самом деле это мой вопрос, я получаю вывод в журнал напрямую и не могу реплицировать, поэтому мне нужен ввод для моего значения с плавающей запятой.   -  person Vishal Zanzrukia    schedule 22.07.2015
comment
@VishalZanzrukia, тогда мой предыдущий ответ был недействительным, извините за это. Я не могу воспроизвести проблему, но, если это поможет, если вы не заметили, в трех описанных вами случаях следующие четыре цифры либо 0, либо 9. Есть ли какое-либо условие (если/пока/для), при котором числа форматируются, иначе нет?   -  person vefthym    schedule 22.07.2015
comment
Единственное, что приходит мне на ум по этому поводу, это известная ошибка точности в примитивном типе данных double. Но API DecimalFormat гарантированно возвращает только то количество цифр, которое указано в шаблоне. Вы уверены, что данные в журнале получены из значений, возвращаемых DecimalFormat.format ?   -  person Little Santi    schedule 22.07.2015
comment
Во-первых, вы используете числа с плавающей запятой (удвоение тоже не является решением) для моделирования цен. НЕ ИСПОЛЬЗУЙТЕ ПЛАВАЮЩИЕ ТОЧКИ ДЛЯ ДЕСЯТИЧНЫХ ЗНАЧЕНИЙ, КАК ДЕНЬГИ, ВСЕГДА ИСПОЛЬЗУЙТЕ BIGDECIMAL. числа с плавающей запятой вместо удвоения еще хуже, потому что вы потеряете цифры, если сумма цены превысит 16 миллионов. Во-вторых, ваш DecimalFormat, похоже, в порядке, так какую версию JDK вы используете и какую машину (Windows, Linux, Mac, Android?)   -  person Thorsten S.    schedule 22.07.2015
comment
@ТорстенС. JDK 1.7 (Линукс)   -  person Vishal Zanzrukia    schedule 22.07.2015


Ответы (1)


Спорадическое появление заставляет меня задаться вопросом, используется ли DECIMAL_FORMAT в нескольких потоках одновременно. Это нет-нет. Однако можно ожидать и неправильных значений.

Возможно, для хорошего порядка также укажите фиксированную локаль (десятичная точка против запятой, разделители тысяч).

И, наконец, float или даже double не подходят для финансового программного обеспечения: эти числа являются приблизительными.

BigDecimal price = new BigDecimal("9.99");
price = price.multiply(BigDecimal.TWO); // 19.98 exact

BigDecimal — это PITA для написания вычислений, но сохраняет свою точность.

person Joop Eggen    schedule 22.07.2015