nan使用math.h函数的long double返回

时间:2017-03-27 01:58:51

标签: c

我试图了解C中的浮点精度。我在math.h函数中尝试升级和降级时遇到了这个问题。

在下面的程序中,我得到了一个使用long double的第一个等式的-nan和第二个得到的结果。我不懂为什么。如果带有长双精度的pow(x,y)返回-nan,为什么(pow(x,y) - z)长双精度会返回正确的结果?

#include <stdio.h>
#include <math.h>

/* equation from xkcd: e to the pi minus pi is 19.999099979 */
int main(void)
{
    printf("f  %#.9f\n",
           pow(2.71828182846F, 3.14159265359F));
    printf("f  %#.9f\n",
           pow(2.71828182846F, 3.14159265359F) - 3.14159265359F);
    printf("d  %#.9lf\n",
           pow(2.71828182846, 3.14159265359));
    printf("d  %#.9lf\n",
           pow(2.71828182846, 3.14159265359) - 3.14159265359);
    printf("ld %#.9Lf\n",
           pow(2.71828182846L, 3.14159265359L));
    printf("ld %#.9Lf\n",
           pow(2.71828182846L, 3.14159265359L) - 3.14159265359L);
    return 0;
}

output:
f  23.140692448
f  19.999099707
d  23.140692633
d  19.999099979
ld -nan
ld 19.999099979

2 个答案:

答案 0 :(得分:3)

如果格式说明符与传递给printf (a)的参数的数据类型不匹配,则为未定义的行为。

如果您使用的是合适的编译器,它会警告您:

myprog.c:15:12: warning: format '%Lf' expects argument of type
    'long double', but argument 2 has type 'double' [-Wformat=]
     printf("ld %#.9Lf\n",
            ^

解决方案是确保参数的正确类型,以通过强制转换来匹配格式:

printf("ld %#.9Lf\n", (long double)pow(2.71828182846L, 3.14159265359L));

或者,更好的是:

printf("ld %#.9Lf\n", powl(2.71828182846L, 3.14159265359L));

后者是首选,因为前者可能(b)涉及精度损失。

(a)请参阅C11 7.21.6 Formatted input/output functions /9了解&#34;未定义的行为&#34;规格:

  

如果任何参数不是相应转换规范的正确类型,则行为未定义。

同一部分的

/7表示%Lf的类型要求:

  

L 指定以下aAeEf,{ {1}},Fg转换说明符适用于 long double 参数。

(b) 5月, 因为标准规定了每个&#34;较小的&#34;浮点类型是下一个&#34;更大&#34;的一个子集。类型。由于子集(与正确的子集相对)意味着&#34;较小或等于超集&#34;,因此double和long double可能是完全相同的底层类型。

然而,假设它 是一个合适的子集是更安全的,因为你在这个假设中并没有真正失去任何东西。

答案 1 :(得分:0)

这是paxdiablo指出的未定义行为。以下是我的编译器显示的警告示例:

$ ./main 
f  23.140692448
f  19.999099707
d  23.140692633
d  19.999099979
ld -0.000000000
ld 19.999099979

这是一个NaN没有出现的例子:

{{1}}