Perl мантисса отличается от других двойников

Я пытаюсь сканировать с плавающей запятой: 13.8518009935297. Первая подпрограмма — моя собственная, вторая — strtod из MacOSX libc, третья — mpf_get_d() из GMP, четвертая — perls numeric.c:Perl_my_atof2().

Я использую этот фрагмент для печати мантиссы:

union ieee_double {
        struct {
                uint32_t    fracl;
                uint32_t    frach:20;
                uint32_t    exp:11;
                uint32_t    sign:1;
        } s;
        double d;
        uint64_t l;
};

 union ieee_double l0;
 l0.d = .... 
 printf("... 0x%x 0x%x\n", l0.s.frach, l0.s.fracl);

Возвращаемые значения для четырех функций:

my-func : 0xbb41f 0x4283d21b 
 strtod : 0xbb41f 0x4283d21c  
GMP     : 0xbb41f 0x4283d21b
perl    : 0xbb41f 0x4283d232

Разница между первыми тремя функциями заключается в округлении. Однако мантисса Perl совершенно не синхронизирована.

Если я снова напечатаю все четыре двойных числа в строке, я получу тот же самый десятичный двойник, числа кажутся равными.

Мой вопрос: разница между my-func, strtod, GMP заключается в округлении. Тем не менее, почему мантисса Perl так сильно не синхронизирована, но все же, если преобразовать ее обратно в десятичную, она снова становится тем же числом. Разница составляет 22, поэтому ее следует записать в десятичной дроби. Как я могу это объяснить?

Добавить: Извините, кажется, я разобрался с проблемой:

  $r = rand(25);
  $t = $p->tokenize_str("$r");

tokenize_str() была моей реализацией преобразования из строки в двойную. Однако perl stringify "$r" выводит $r как 13.8518009935297, что уже является усечением. Фактическое значение $r отличается, поэтому, когда я в конце бинарных файлов $t с $r я получаю значения, которые расходятся.


person Konrad Eisele    schedule 30.07.2013    source источник
comment
Согласно этой странице, эта мантисса на самом деле имеет 2 больше цифр десятичной точности, чем вы показываете: 13.851800993529700. Версия Perl равна 13.851800993529740. Так что разница не существенна на вашем уровне точности. Тем не менее, это интересный вопрос, чем отличается Perl.   -  person Jim Garrison    schedule 30.07.2013
comment
Извините, разобрался с ошибкой (см. выше). Все равно спасибо за ответ...   -  person Konrad Eisele    schedule 30.07.2013


Ответы (1)


Вот некоторый код Perl, чтобы ответить на ваш вопрос:

perl -le '($frac1, $frach)=unpack("II", pack "d", .0+"13.8518009935297");
print sprintf("%d %d 0x%03x 0x%04x", ($frach >> 31)&1, ($frach>>20)&0x5ff, $frach & 0xfffff, $frac1)'

-> 0 1026 0xbb41f 0x4283d21c

Perl дает тот же результат, что и strtod. Разница заключалась в ошибке, которую вы указали в приложении.

person BOC    schedule 19.08.2013