为什么 mpfr_printf 不同于 printf 的十六进制浮点数(%a 转换说明符)?
Why is mpfr_printf different than printf for hex float (%a conversion specifier)?
我正在比较来自常规浮点运算的值并使用高精度 MPFR 数字作为基线。打印时,我很困惑为什么下面的代码输出不同。
MPFR documentation表示输出说明符是
‘a’ ‘A’ hex float, C99 style"
所以我假设它的打印结果与 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
将它们都解析为相同的值,但我找不到任何文档来解释它们为何不同。
哪一个是规范的?
没有规范形式。 C 标准没有规定第一个数字,只是对于普通数字它必须是非零的。 C 2018 7.21.6.1 8 表示,在 a
和 A
转换说明符中:
A double argument representing a floating-point number is converted in the style [-]0xh.hhhhp±d, where there is one hexadecimal digit (which is nonzero if the argument is a normalized floating-point number and is otherwise unspecified) before the decimal-point character and the number of hexadecimal digits after it is equal to the precision;…
为了完成关于缺少规范形式的回答,我尝试提供各种选择。
对于 GNU libc,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 实用程序,我在 2007 年进行的 printf "%a\n" 256
测试显示了 3 个不同的结果:
0x1p+8
printf
bash 3.1.17 under Linux/x86 和 bash 2.05b.0 under Mac OS X (PPC) 10.4.11;
0x2p+7
以及来自 coreutils 6.9 的 printf
Mac OS X (PPC) 10.4.11;
0x8p+5
以及 Linux/x86. 下 coreutils 5.97 的 printf
关于 GNU MPFR,最初的选择是让第一个数字尽可能大,即在 8 到 15 (= F) 之间,这样可以获得尽可能短的尾数字符串。但是好像改成了指数是4的倍数,精度字段为0的时候除外。不知道为什么...
我正在比较来自常规浮点运算的值并使用高精度 MPFR 数字作为基线。打印时,我很困惑为什么下面的代码输出不同。
MPFR documentation表示输出说明符是
‘a’ ‘A’ hex float, C99 style"
所以我假设它的打印结果与 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
将它们都解析为相同的值,但我找不到任何文档来解释它们为何不同。
哪一个是规范的?
没有规范形式。 C 标准没有规定第一个数字,只是对于普通数字它必须是非零的。 C 2018 7.21.6.1 8 表示,在 a
和 A
转换说明符中:
A double argument representing a floating-point number is converted in the style [-]0xh.hhhhp±d, where there is one hexadecimal digit (which is nonzero if the argument is a normalized floating-point number and is otherwise unspecified) before the decimal-point character and the number of hexadecimal digits after it is equal to the precision;…
为了完成关于缺少规范形式的回答,我尝试提供各种选择。
对于 GNU libc,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 实用程序,我在 2007 年进行的 printf "%a\n" 256
测试显示了 3 个不同的结果:
0x1p+8
printf
bash 3.1.17 under Linux/x86 和 bash 2.05b.0 under Mac OS X (PPC) 10.4.11;0x2p+7
以及来自 coreutils 6.9 的printf
Mac OS X (PPC) 10.4.11;0x8p+5
以及 Linux/x86. 下 coreutils 5.97 的
printf
关于 GNU MPFR,最初的选择是让第一个数字尽可能大,即在 8 到 15 (= F) 之间,这样可以获得尽可能短的尾数字符串。但是好像改成了指数是4的倍数,精度字段为0的时候除外。不知道为什么...