Проблема с получением цифр в двойной переменной

У меня возникла небольшая проблема с функцией, которая мне нужна в моей Java-программе. Я хочу проверить общее количество цифр, которое имеет «двойная» переменная. (например: 5 должен возвращать 1, 5.0034 должен возвращать 5, а 2.04 должен возвращать 3.) Моя функция такова:

private int getDoubleLength (double a) {
        int len = 0;
        while (a != (int) a) {
            a *= 10;
        }
        while (a > 1) {
            len ++;
            a/=10;
        }
        System.out.println(String.format("Double %f has %d digits.",a,len));
        return len;
    }

Теперь это работает отлично, но когда я делаю некоторые математические вычисления, вы получаете небольшие ошибки удвоения: я делю 10 на cos(60), что равно 0,5. Ответ должен быть 20.0, но программа выдает 20.000000000000004 (это число я скопировал). Мой цикл while застревает, и программа зависает.

Есть идеи? (Или другие отличные решения для проверки цифр числа!)


person Hidde    schedule 13.05.2011    source источник
comment
двойное значение не может иметь более 17 цифр точности, поэтому вы должны остановиться, когда доберетесь до 17. Другая проблема, с которой вы столкнулись, заключается в том, что двойное число может быть больше, чем Integer.MAX_VALUE, что приведет к тому, что ваш первый цикл будет повторяться бесконечно.   -  person Peter Lawrey    schedule 13.05.2011


Ответы (4)


Двойники и поплавки, а также операции с ними не точны, поэтому всегда будут небольшие ошибки по сравнению с алгебраическими вычислениями. Если вы используете косинусы и т. д., вам всегда придется иметь дело с этими ошибками округления, которые должны быть описаны в любой книге или веб-тексте по численному анализу. Если вы используете простые арифметические операции, просмотрите java.lang. BigDecimal

Подробнее о том, как хранятся значения с плавающей запятой, см. в разделе Что каждый Специалист по информатике должен знать об арифметике с плавающей запятой

person mmmmmm    schedule 13.05.2011

toString().length() должен решить эту проблему,
не забудьте вычесть '.' если он есть и не должен считаться

person amit    schedule 13.05.2011
comment
+1 , но разве это не должно быть toString.length - 1 (по сути)? - person Kai Huppmann; 13.05.2011
comment
@Kai: я упомянул об этом в своем ответе (вторая строка) - person amit; 13.05.2011

Вот как я реализовал свое простое преобразование в строку, когда двойное значение было возвращено большой строкой с экспоненциальным представлением. т. е. 20000000 вернет 2.0E+7, а разделение затем разделит его отсюда, что приведет к неправильному счету. Я использовал BigDecimal и toPlainString() метод

protected int countDecimalDigits(Double d) {
    BigDecimal deci = BigDecimal.valueOf(d);
    int integerPlaces = 0;
    int decimalPlaces = 0;
    String text = deci.toPlainString();

    String[] integerDecimalSplit = text.split("\\.");
    if (null != integerDecimalSplit[0]) {
        integerPlaces = integerDecimalSplit[0].length();
    }
    if (integerDecimalSplit.length > 1) {
        decimalPlaces = integerDecimalSplit[1].length();
    }
    return integerPlaces + decimalPlaces;
}
person mel3kings    schedule 20.04.2015

Это проблема округления. Я бы использовал строки, подсчитал символы и решил, какие цифры считать значимыми.

person xdevient    schedule 13.05.2011