?/4 的莱布尼茨公式

Sou*_*aji 3 c double

我被要求打印莱布尼茨公式的总和,直到该系列的第 n 项正确到小数点后 15 位。在微积分中,莱布尼茨公式的 ? 由下式给出: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;
}
Run Code Online (Sandbox Code Playgroud)

谁能告诉我为什么我不能达到小数点后 15 位的精度?我的目标不是打印 pi/4 的值,我只需要打印给定 n 的总和

chu*_*ica 5

问:为什么...精度达到小数点后 15 位?
答:要在小数点后显示15 位小数,请使用 format "%0.15f"。要计算 15 位小数的收敛,至少n需要非常大。

正如@user3386109 所提到的,“结果中的错误以 1 / (2n+1) 为界”,因此大约需要 5e14 次迭代。(粗略估计:在我的 PC 上需要 10 天。)由于典型double的精度约为 pow(2,53) 中的 1 部分或 9e15 中的 1 部分,double因此正在达到计算的限制。下面的代码比较了计算顺序以减少误差,但充其量,9e15中误差仍然至少为0.5部分。

由于级数的项在极限附近振荡,因此在n迭代后停止时,可以添加下一次迭代的 1/2 的最终迭代。这将获得大约 1 位的准确度。

正如其他人所提到的,存在其他方法来计算 ? 收敛得更快。


根据@user3386109 的良好观察更新。

在对项求和时,代码可以按各种顺序对它们求和。下面的 2 种方法说明,当先将小项加在一起时,可以更早地获得适度更稳定的结果。我希望最多只有 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
Run Code Online (Sandbox Code Playgroud)