我想了解C如何处理浮点数的精度损失。
这是我的简单代码:
#include <stdio.h>
#include <math.h>
int main ()
{
double a;
int i;
i = 7;
a = sqrt(i);
printf("i = %d, a = %lf\n", i, a);
printf("a * a = %lf\n", a*a);
a = 2.645751;
printf("a * a = %lf\n", a*a);
return(0);
}
以下是cc之后的结果
i = 7,a = 2.645751
a * a = 7.000000
a * a = 6.999998
如果直接分配了一个2.645751的浮动数字,a * a的结果对我来说是可以理解的。
但是如果a被分配了sqrt(7),为什么a * a的输出没有精度损失?
这对我来说很难理解。
你的困惑来自a
实际上持有的内容以及printf
默认精确度的内容。来自man 3 printf
“如果缺少精度,则将其视为6”。因此,当您使用%lf
(其应该只是%f
,因为%f
已经是double
的格式说明符)打印时,您只能看到a
的值为默认的6位精度。 (四舍五入)
在你调用a
之后,2.645751
不包含a = sqrt(i);
- 这只是你的printf
语句的默认精确输出。您可以通过为输出指定更长的精度来清楚地看到这一点,例如
printf("i = %d, a = %.10f\n", i, a);
输出:
i = 7, a = 2.6457513111
因此,您需要清楚地了解实际double
中包含的内容很可能不是您在使用默认格式说明符和默认精度的printf
时看到的内容。 double
值(64位)表示1-bit
符号位,11-bit
归一化指数和52-bit
尾数。并非所有数字都能够被准确表示(仅仅由于比特的限制来表示每个可能的数字)。
一个好的,但可以说是相当干燥的阅读,更进一步的参考是What Every Programmer Should Know About Floating-Point
如果这有助于您的理解,或者您是否还有疑问,请告诉我。我们很乐意进一步提供帮助。
您指定的a
为double,具有非常长的精度,然后是您指定为硬编码的精度。因此,您可以看到硬编码数字的精度误差。与此同时,使用sqrt()
的精度误差并不是那么明显,尽管printf()
没有完全显示。