2 февраля 2011 г.

2.2250738585072012e-308

Вчера познакомился с этим числом и понял, что срочна нужна рубрика «Занимательные числа». Этой заметкой ее и открываю.

2.2250738585072012e-308


На этом числе зацикливается парсер дабл-чисел в Яве. К примеру строчка «double d = 2.2250738585072012e-308;» вешает эклипс и любой компилятор. Им же можно ломать уже запущенные приложения (если в них читаются даблы). Любопытные комментаторы исходной статьи (см. ниже) уже надругались на гугл-доком, записав это число в ячейку таблицы.

Java зависает на 2.2250738585072012e-308 (хабр)

источник: http://habrahabr.ru/blogs/java/112948

Константин Прайссер (Konstantin Preisser) недавно обнаружил нечто весьма любопытное: Java — и рантайм и компилятор — входит в бесконечный цикл при конвертации десятичного 2.2250738585072012e-308 в double. По идее, число должно быть преобразовано в 0x1p-1022, то есть Double.MIN_VALUE. Однако, Java зависает на 0x0.fffffffffffffp-1022, самом большом денормализованном числе для double.

Бесконечный цикл в runtime


class RuntimeHang {
    public static void main(String[] args) {
        System.out.println("Test:");
        double d = Double.parseDouble("2.2250738585072012e-308");
        System.out.println("Value: " + d);
    }
}

Бесконечный цикл во время компиляции


(Если вы хотите опробовать это в Eclipse, не забудьте сначала всё сохранить, а то с его теневой компиляцией и опомниться не успеете — прим. перев.)
class CompilationHang {
    public static void main(String[] args) {
        double d = 2.2250738585072012e-308;
        System.out.println("Value: " + d);
    }
}

Под катом рассуждения автора насчёт причин этого явления.

В чём же дело?


Константин выяснил, что по крайней мере в рантайме проблема кроется в «цикле коррекции» вFloatingDecimal.java. Он пишет:

Если закомментировать эту часть, в рантайме зависания больше нет, посколькуDouble.parseDouble(String s), который вызываетsun.misc.FloatingDecimal.readJavaFormatString(s).doubleValue() — код на чистой java, ничего нативного. Но там используется артифметика чисел с плавающей точкой, так что дело может быть в настройках компилярота, в котором компилировали JRE и javac.

Без цикла коррекции выходят такие биты (big endian):
00000000 00001111 11111111 11111111 11111111 11111111 11111111 11111111

То есть, число конвертируется в самое большое денормализованное число с плавающей точкой, поскольку экспонента нулевая. Без цикла коррекции то же самое происходит и с 2.2250738585072013e-308, однако если цикл раскомментировать, то сконвертируется правильно:
00000000 00010000 00000000 00000000 00000000 00000000 00000000 00000000

Комментариев нет:

Отправить комментарий