关于C#:π/ 4的莱布尼兹公式

Leibniz formula for π/4

我被要求打印列布尼兹公式的和,直到系列的第n项,精确到15位小数。在微积分中,π的列布尼兹公式由下式给出:1-1/3+1/5-1/7+…=π/ 4

这是我的密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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
"
,s);
    return 0;
}

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


问:为什么…精确到小数点后15位?A:小数点后15位显示,格式为"%0.15f"。要计算15个小数位的收敛性,至少n需要非常大。

如@user3386109所述,"结果中的错误以1/(2n+1)"为界,因此需要大约5e14次迭代。(粗略估计:在我的电脑上10天)由于典型的double在POW(2,53)中的精度约为1份,或在9E15中的精度约为1份,因此double计算的限值已达到。下面的代码比较了计算顺序以减少误差,但在9e15中,误差最多仍将是0.5个部分。

当序列的项围绕极限振荡时,在n次迭代后停止时,可以添加1/2的最后一次迭代,即下一次迭代。这将获得大约1位的精度。

正如其他人所提到的,还有其他方法可以计算π,它的收敛速度更快。

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

在求和术语时,代码可以按不同的顺序求和。下面的两种方法说明,当先将小项求和时,可以得到一个稍微更稳定的结果。我最多只能期待一个1或2点更好的答案。

这是使用float重新完成的,因为在最后几个位稳定之前,不会出现小的改进。对于double和这个缓慢收敛的序列,这将花费太长的时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//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);
  static const fp pic = 3.1415926535897932384626433832795;
  const char *format ="%s %0.9f
"
;
  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


更改您的printf语句,以在小数点后打印更多的值。

例如,使用

1
2
printf("%30.28Lf
"
,s);

将数字打印到小数点后28位。使用n=25,我得到了以下输出。

1
0.7953941713587578038252220991