Почему mpfr_printf отличается от printf для шестнадцатеричного числа с плавающей запятой (% спецификатор преобразования)? - PullRequest
2 голосов
/ 10 июля 2020

Я сравниваю значения из обычных арифметических чисел с плавающей запятой c и использую высокоточное число MPFR в качестве базовой линии. При печати я не понимаю, почему следующий код выводится по-другому.

Документация MPFR говорит, что спецификаторы вывода:

'a' 'A' шестнадцатеричное число с плавающей запятой, стиль C99 "

Итак, я предполагаю, что он печатает так же, как printf. Однако это не так:

#include <boost/multiprecision/mpfr.hpp>

#include <mpfr.h>

using namespace boost::multiprecision;

int main (int argc, char* argv[])
{
    double               a = 254.5;
    mpfr_float_1000 mpfr_a = 254.5;

    mpfr_t t;
    mpfr_init2(t, 3324); // 1000 decimal precision
    mpfr_set_d(t, a, MPFR_RNDN);

    printf("double:\t%a\n", a);
    mpfr_printf("mpfr_t:\t%RNa\n", t);
    mpfr_printf("boost:\t%RNa\n", mpfr_a);
}

Выводит:

double: 0x1.fdp+7
mpfr_t: 0xf.e8p+4
boost:  0xf.e8p+4

Это не огромный сделка, потому что sscanf анализирует их как одно и то же значение, но я не смог найти никакой документации, объясняющей, почему они разные.

Какой из них канонический?

Ответы [ 2 ]

3 голосов
/ 10 июля 2020

Канонической формы нет. Стандарт C не регулирует первое di git за исключением того, что он должен быть ненулевым для нормальных чисел. C 2018 7.21.6.1 8 говорит о спецификаторах преобразования a и A:

A double аргумент, представляющий число с плавающей запятой, преобразуется в style [-] 0xh.hhhhp ± d , где перед символом десятичной точки стоит один шестнадцатеричный di git (который не равен нулю, если аргумент является нормализованным числом с плавающей запятой и в противном случае не указан) и количество шестнадцатеричных цифр после него равно точности;…

1 голос
/ 12 июля 2020

Чтобы завершить ответ об отсутствии канонической формы, я пытаюсь представить различные варианты.

Для GNU lib c, stdio-common/printf_fphex.c содержит:

  /* We have 52 bits of mantissa plus one implicit digit.  Since
     52 bits are representable without rest using hexadecimal
     digits we use only the implicit digits for the number before
     the decimal point.  */

Но обратите внимание, что не все форматы используют неявный бит: формат расширенной точности x87 (long double на x86) - нет. Так что это может привести к некоторой несогласованности.

Для утилиты printf POSIX тесты printf "%a\n" 256, которые я провел в 2007 году, показали 3 разных результата:

  • 0x1p+8 с printf встроенный bash 3.1.17 под Linux / x86 и bash 2.05b.0 под Ma c OS X (PP C) 10.4.11;
  • 0x2p+7 с printf из coreutils 6.9 под Ma c OS X (PP C) 10.4.11;
  • 0x8p+5 с printf из coreutils 5.97 под Linux / x86.

Что касается GNU MPFR, то первоначальный выбор заключался в том, чтобы первое di git было как можно большим, то есть между 8 и 15 (= F), что позволяет получить самую короткую возможную значимую строку. Но похоже, что это было изменено, чтобы иметь показатель, кратный 4, за исключением случаев, когда поле точности равно 0. Я не знаю, почему ...

...