为什么snprintf不能用于双精度0x1p-1074 ...?

时间:2018-08-09 07:36:23

标签: c linux glibc

#include<stdio.h>

int main()
{
        char *nstring = NULL;
        int n = 0, i = 0;
        double value = 0x1p-1074;
        char buf[128] = {0};

        n = snprintf(buf, 128,"%.*f", 8, value);

        while(i < n) {
                printf("buf[%d] : Data [%c]\n", i, buf[i]);
                i++;
        }

        return 0;
}

在这里,我正在使用snprintf将双value = 0x1p-1074格式化为buf。但是当我执行上面的代码时,我得到了:

buf[0] : Data [0]
buf[1] : Data [.]
buf[2] : Data [0]
buf[3] : Data [0]
buf[4] : Data [0]
buf[5] : Data [0]
buf[6] : Data [0]
buf[7] : Data [0]
buf[8] : Data [0]
buf[9] : Data [0]

我尝试如下使用glibc函数fcvt_r__snprintf()来格式化0x1p-1074

 n = snprintf (buf, len, "%.*" FLOAT_FMT_FLAG "f", MIN (ndigit, NDIGIT_MAX),
                  value);

有人可以解释FLOAT_FMT_FLAG的用法吗?我还尝试在glib源(__snprintf())中将snprintf()替换为misc/efgcvt_r.c,并添加一些printf;给出我期望的输出:

buf[0] : Data [4]
buf[1] : Data [.]
buf[2] : Data [9]
buf[3] : Data [4]
buf[4] : Data []
buf[5] : Data []
buf[6] : Data []
buf[7] : Data []

这是预期的输出。我可以在测试程序中使用FLOAT_FMT_FLAG吗?还是有其他方法可以获得与glibc源代码相同的输出?

1 个答案:

答案 0 :(得分:2)

0x1p-1074(在DBL_TRUE_MIN中定义为<float.h>的IEEE-754 binary64 double的最小可能的正常值)非常接近0。使用%f进行打印会产生没有指数的十进制表示形式,如果只需要8个小数位,则它们都将是0,并且输出将是预期的0.00000000

您似乎假设%ffcvt应该产生相同的数字。仅对于幅度在110之间的数字是正确的。对于您的示例,fcvt产生有效数字4.94,但十进制指数为-324

FLOAT_FMT_FLAG是一个非标准的GNU扩展,用于告诉printf传递的浮点值是long double。自C99起,标准C将此标志定义为L

如果您的目标是使用不提供它的C库来生成fcvt的输出,则可以使用%.8e并去除指数部分。