尝试打印超过15个十进制数字PI
会导致在十五分之一后打印错误的小数位数。尽管分配了30个正确的十进制值,尽管使用long double
来保存该值。以下测试用例清楚地显示了错误。
这是出乎意料的。如果数字中有任何错误,我不希望在耗尽IEEE-754有效数字后第25位之前看到任何错误。在这里可以解释的规则是什么,我可以打印回我刚刚分配给下面的sPI的相同30位数字。这也会影响打印M_PI
中包含的math.h
表示的能力。
#include <stdio.h>
int
main (void) {
// static PI approximation (glibc man 1.17)
long double sPI = 3.14159265358979323846264338327;
char strPI[] = "3.14159265358979323846264338327";
printf ("\n %s (strPI - string - correct)\n", strPI);
printf (" %.29Lf (sPI - long double - INCORRECT)\n\n", sPI);
return (0);
}
输出:
3.14159265358979323846264338327 (strPI - string - correct)
3.14159265358979311599796346854 (sPI - long double - INCORRECT)
^^^^^^^^^^^^^^
据推测,此十进制错误适用于任何小数超过16的十进制数。当作为字符串打印时,PI打印正常(显然),但是当打印为双精度时 - 小数精度在小数点后15位分解。造成这种情况的原因是什么?
非常有趣,因为建议在浮点文字的末尾添加L
确实有帮助:
3.14159265358979323846264338327 (strPI - string - correct)
3.14159265358979323851280895941 (sPI - long double - INCORRECT)
提供了3个额外的精度小数。为清楚起见,这是在旧的AMD Phenom X4 9850上的Linux 3.14.1内核,gcc 4.8.2上运行。(AMD基于Turion的笔记本电脑和英特尔P4给出相同的结果)
尝试分配给quadmath.h
的{{1}}和__float128
类型,结果与长双倍相同。还有一些数字可用,但精度仍然在第19位数字上破坏:
sPI
答案 0 :(得分:5)
您没有将'long double'值存储到变量中,而是默认double
。编译器读取浮点值,将其存储为默认类型,然后仅将其转换为 long double“。将其值与“正常”分配的double
进行比较时,您可以看到这一点。
要提示编译器将常量存储为long double
,请在浮点常量的末尾添加修饰符后缀L
或l
。
示例:
#include <stdio.h>
int main (void)
{
// static PI approximation (glibc man 1.17)
double sPI_d = 3.14159265358979323846264338327;
long double sPI = 3.14159265358979323846264338327;
long double sPI_L= 3.14159265358979323846264338327L;
char strPI[] ="3.14159265358979323846264338327";
printf ("\n %s (strPI - string - correct)\n", strPI);
printf (" %.29f (sPI - double)\n", sPI_d);
printf (" %.29Lf (sPI - long double - INCORRECT)\n", sPI);
printf (" %.29Lf (sPI - long double - BETTER)\n", sPI_L);
return 0;
}
输出:
3.14159265358979323846264338327 (strPI - string - correct)
3.14159265358979311599796346854 (sPI - double)
3.14159265358979311599796346854 (sPI - long double - INCORRECT)
3.14159265358979323851280895941 (sPI - long double - BETTER)
另请参阅What is the precision of long double in C++? - 对于long double
,您不能指望超过18位有效数字。
答案 1 :(得分:3)
双精度浮点值表示为64位值,有限精度为15-16位十进制数。因此,long double
似乎在您的系统上实现为64位双精度。
如果您不熟悉这些问题,我强烈推荐David Goldberg的永恒文章What Every Computer Scientist Should Know About Floating-Point Arithmetic。