M_PI不精确

时间:2018-07-14 22:58:06

标签: c math.h

我正在尝试打印M_PI,但我认为我没有使用正确的格式说明符。输出应为:3.14159265358979323846但我得到3.14159265358979300000。

int main(void)
{
    printf("%.20f\n", M_PI);
    return 0;
}

我已经尝试使用%Lf,%Lg,%e,%g,但是它们都不起作用,所以我不确定此错误是否来自格式说明符或它是否与硬件有关。我正在使用。

4 个答案:

答案 0 :(得分:4)

假设您的编译器将double浮点类型映射到IEEE 754双精度,则double的精度为53个二进制数。浮点数以2为基数表示这一事实意味着它与一组可以表示为double且具有短十进制表示形式的数字不同。特别是,最接近π的double的精确值仅具有53个二进制精度的紧凑表示,但以十进制表示为3.141592653589793115997963468544185161590576171875。这不是π到50的十进制数字的近似值!它是π的近似值,精度为53个二进制数字,这意味着大约17个第一个十进制数字是正确的,而其他数字仅存在于此,因为表示M_PI的基数2和我们现在讨论其价值的基数10。

这意味着您可以期望实现质量 printf的实现3.14159265358979311600。请注意,这与您在问题中所期望的字符串不完全相同,而是将十进制表示形式四舍五入为.的实际值M_PI之后的20位数字。无论如何,您可以期望 quality printf实现能够打印出显示double的确切值所必需的所有十进制数字,尽管在最坏的情况下{{3 }}。

C标准there can be 750 or so所有printf实现都具有此属性:

  

对于e,E,f,F,g和G转换,如果有效位数   十进制数字最多为DECIMAL_DIG,则结果应为   正确舍入。如果有效的十进制数字为   大于DECIMAL_DIG,但源值可精确表示   用DECIMAL_DIG数字表示,则结果应该是精确的   尾随零表示。否则,源值为   由两个相邻的十进制字符串L

更容易实现最多打印double的确切值的前17个十进制数字,然后打印零的实现,并且C标准允许这种实现。这可能是编译器发生的情况。 (采用此快捷方式的编译器通常也不会实现“当前舍入方向”约束。)

答案 1 :(得分:1)

只有非常高的精度,双精度浮点数才具有。少于20位,因此在某些时候,无论您要求多少位精度,您都会得到无意义的噪声或全零。

答案 2 :(得分:1)

我知道已经回答了这个问题,但是,假设您使用的是c ++,则可以使用

#define _USE_MATH_DEFINES 
#include <cmath>
#include <iostream>
using namespace std;

现在在类或int main()中;

double g = M_PI;
cout << setprecision(50) << g << endl;

输出:

3.141592653589793115997963468544185161590576171875

答案 3 :(得分:0)

double,在遵循IEEE-754的大多数体系结构中都只有64位,一个为符号,11为指数,尾数为52位(53,因为第一个有效位始终为{ {1}},并且由于这个原因未包含在格式中,因此您以53为底的2位有效数字),这意味着大约(以10为底的1个有效数字){{1}的近似值}的精度应该类似于。

(52+1)/ln(10)*ln(2) ~= 15.95

这是您获得的PI精确数字的近似值。您获得的值和PI的实际值之间存在一个M_PI的近似差异,这可能是由于算法3.141592653589793 用于获取该数字的十进制版本。

但是您不能期望从IEEE-754实现中获得更准确的结果,因此您得到的答案受您要求的位数的影响。

顺便说一句,您是否尝试过使用2 * 10^(-16)格式的字符串?至少在gcc中,您会得到很多非零数字,以完成您要求的全部精度(从2开始,假设从最后一位起,您全都是零数字)。在MSVC中,我知道到了零填充(使用某种算法)的时间,这就是发生在您身上的事情。但是,总要注意的是,在IEEE-754实现的64位浮点数上,结果上最多有16个有效数字(确切地说,小于16),因为结果与之接近,但是