为什么sqrt()指定的浮点数没有精度损失? [关闭]

问题描述 投票:1回答:2

我想了解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的输出没有精度损失?

这对我来说很难理解。

c precision
2个回答
6
投票

你的困惑来自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

如果这有助于您的理解,或者您是否还有疑问,请告诉我。我们很乐意进一步提供帮助。


0
投票

您指定的a为double,具有非常长的精度,然后是您指定为硬编码的精度。因此,您可以看到硬编码数字的精度误差。与此同时,使用sqrt()的精度误差并不是那么明显,尽管printf()没有完全显示。

© www.soinside.com 2019 - 2024. All rights reserved.