我被要求将Leibniz公式的总和打印到系列的第n项,正确到15位小数。在微积分中,π的Leibniz公式由下式给出: 1 - 1/3 + 1/5 -1/7 + ... =π/ 4
这是我的代码
#include<stdio.h>
#include<math.h>
int main()
{
int n,i;
long double s=0;
scanf("%d",&n);
for(i=0;i<n;i++){
s+=(long double)pow(-1,i)/(2*i+1);
}
printf("%Lf\n",s);
return 0;
}
有谁能告诉我为什么我无法达到小数点后15位的精度? 我的目的不是打印pi / 4的值,我只需打印给定n的总和
答案 0 :(得分:4)
问:为什么......精度达到小数点后15位?
答:要小数点后使用格式"%0.15f"
显示 15位小数。要计算15个小数的收敛点,n
至少需要非常大。
如@ user3386109所述,“结果中的错误以1 /(2n + 1)为界”,因此需要大约5e14次迭代。 (粗略估计:我的PC上有10天。)由于典型的double
精度约为1分(动力学)(2,53分)或1分(9分15分),因此达到了double
计算的极限。下面的代码比较了计算顺序以减少错误,但最好,错误在9e15中仍然至少为0.5个部分。
当系列的项振荡极限时,在n
次迭代后停止时,可以添加下一次迭代的1/2的最终迭代。这将获得大约1位的准确度。
正如其他人所提到的,存在其他方法来计算收敛更快的π。
根据@ user3386109的良好观察结果更新。
在对术语进行总结时,代码可以按各种顺序对它们求和。下面的两个方法说明,在首先将小项汇总在一起时,可以更早地实现适度更稳定的结果。我希望最好只有1或2位更好的答案。
这是使用float
重新完成的,因为在最后几位稳定之前,小改进不会出现。使用double
和这个缓慢收敛的系列,这将花费太长时间。
//Leibniz formula for pi/4
typedef float fp;
fp LeibnizForward(unsigned n) {
volatile fp sum = 0.0;
fp sign = 1.0;
unsigned i = 1;
while (n-- > 0) {
sum += sign / i;
sign = -sign;
i = (i + 2);
}
return sum;
}
fp LeibnizReverse(unsigned n) {
volatile fp sum = 0.0;
fp sign = 1.0;
unsigned i = 2 * n - 1;
if (n % 2 == 0)
sign = -sign;
while (n-- > 0) {
sum += sign / i;
sign = -sign;
i = (i - 2);
}
return sum;
}
void PiTest(unsigned n) {
printf("%u\n", n);
static const fp pic = 3.1415926535897932384626433832795;
const char *format = "%s %0.9f\n";
printf(format, "pi-", nextafterf(pic,0));
printf(format, "pi ", pic);
printf(format, "pi+", nextafterf(pic,4));
fp pif = LeibnizForward(n) * 4;
printf(format, "pif", pif);
fflush(stdout);
fp pir = LeibnizReverse(n) * 4;
printf(format, "pir", pir);
fflush(stdout);
}
int main(void) {
PiTest(0);
PiTest(1);
PiTest(10);
PiTest(100);
PiTest(1000);
PiTest(10000);
PiTest(100000);
PiTest(1000000);
PiTest(10000000);
PiTest(100000000);
return 0;
}
0
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 0.000000000
pir 0.000000000
1
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 4.000000000
pir 4.000000000
10
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.041839600
pir 3.041839600
25
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.181576490
pir 3.181576729
100
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.131592512
pir 3.131592751
1000
pi- 3.14 1592503
pi 3.14 1592741
pi+ 3.14 1592979
pif 3.14 0592575
pir 3.14 0592575
10000
pi- 3.141 592503
pi 3.141 592741
pi+ 3.141 592979
pif 3.141 498566
pir 3.141 492605
100000
pi- 3.1415 92503
pi 3.1415 92741
pi+ 3.1415 92979
pif 3.1415 85827
pir 3.1415 82489
1000000
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 5364
pir 3.14159 1549
10000000
pi- 3.14159 2503 previous float
pi 3.14159 2741 machine float pi
pi+ 3.14159 2979 next float
pif 3.14159 6794
pir 3.14159 2503
100000000 Additional iterations do not improve the result.
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 6794
pir 3.14159 2503
1000000000
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 6794
pir 3.14159 2503
答案 1 :(得分:0)
更改printf
语句以打印小数点后的更多值。
例如,使用
printf("%30.28Lf\n",s);
将数字打印到小数点后的28位。使用n=25
,我得到了以下输出。
0.7953941713587578038252220991