Использование форматирования в стиле Java Double.toString () с большим количеством цифр (DecimalFormat не работает с числами низкой точности) - PullRequest
5 голосов
/ 29 июля 2011

Центральная проблема заключается в том, что у меня есть серия двойных чисел, которые мне нужно регистрировать, каждая из которых имеет разное количество значащих цифр. Числа сильно различаются по количеству значимых цифр. Некоторые имеют 0 (например, 5257), некоторые имеют 2 (например, 1308.75), некоторые имеют вплоть до 7 (например, 124.1171875). В основном все от 0 до 7 значащих цифр после десятичной дроби.

Стандартный Double.toString () отлично работает на всем, НО те, которые имеют 7 значащих цифр. То есть до 6 цифр, все значащие цифры печатаются без каких-либо незначительных цифр. Но для тех, у которых 7 значащих цифр, toString () округляет последнюю цифру. * Т.е. 1003 *

5257 -> "5257"
1308.75 -> "1308.75"
124.1171875 -> "124.117188"

Конечно, я попытался использовать DecimalFormat ("#. #######"), и это решило проблему пропуска значащих цифр, но для многих двойных значений низкой точности он печатал незначительные цифры. * Т.е. 1006 *

1308.75 -> "1308.7499998"

Это также неприемлемо, так как 1) оно тратит значительное количество места (как правило, журнал> 2 ГБ данных в день) и 2) портит приложения, используя журналы.

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

Есть идеи? Спасибо

Ответы [ 3 ]

7 голосов
/ 29 июля 2011

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

Как это происходит, я не могу воспроизвести ваше поведение 1308.75 в DecimalFormat, что меня не удивляет, потому что это значение точно представлено как double. Фактически, DecimalFormat, похоже, все равно применяет некоторую эвристику, поскольку даже 1308.76 получается как 1308.76 - что удивляет меня, поскольку значение фактическое равно 1308.759999999999990905052982270717620849609375. Это означает, что если вы используете 1308.7599999999999 в своем коде, он получится как 1308.76, потому что это точно такое же значение, что касается double. Если вам необходимо различать эти два значения, вы обязательно должны использовать BigDecimal.

Также обратите внимание, что 1308.75 имеет 6 значащих цифр - у него 2 десятичных знаков . Стоит быть осторожным, чтобы различать эти два понятия.

3 голосов
/ 29 июля 2011

Мне показалось немного странным, поэтому я вышел и проверил.Я попробовал этот код:

public class MySimpleTest
{
    public static void main(String args[])
    {
        format(5257);
        format(1308.75);
        format(124.1171875);
    }

    private static void format(double d)
    {
        DecimalFormat df = new DecimalFormat("##.#######");
        System.out.println("" + d + " -> " + df.format(d));
    }
}

И он дал мне такой результат:

5257.0 -> 5257
1308.75 -> 1308.75
124.1171875 -> 124.1171875

Вы, вероятно, тестировали с "##. ######" (только 6 #s после точки), или ваш номер мог содержать завершающие цифры.Дело в том, что форматы ##. ####### и ##. 0000000 округляют последнюю десятичную точку (например, 124.11718755 будет округлено до 124.1171876 перед форматированием).Если вы хотите, чтобы оно было обрезано, попробуйте сначала его обрезать, выполнив что-то вроде этого:

double d = 124.1171875999999;
org.apache.commons.math.util.MathUtils.round(d, 6, java.math.BigDecimal.ROUND_DOWN);
DecimalFormat df = new DecimalFormat("##.#######");
System.out.println("" + d + " -> " + df.format(d));
0 голосов
/ 29 июля 2011

Кроме того, что упомянул Джон Скит, почему бы не сохранить массив DecimalFormat, каждый из которых состоит из нескольких цифр?

...