神奇的求圆周率代码
今天是圆周率日,我们就来讲一讲关于圆周率的故事吧。
很久以前,笔者看到了一段惊为天人的代码,可以求出圆周率的前 800 位(修改参数可以实现任意精度):1
2
3int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
f[b]=d%--g,d/=g--,--b;d*=b);}
经过考证,这段代码的作者是 Dik T. Winter。下面我们来看看它是如何工作的。
在 C 语言中,for
循环和 while
循环可以互相代替。这里涉及到 for
循环的执行顺序。例如1
2
3for (statement1; statement2; statement3) {
statements;
}
上面的 for
语句可以用下面的 while
语句来代替:1
2
3
4
5statement1;
while (statement2) {
statements;
statement3;
}
而逗号运算符和 --
运算符的功能也是需要注意的。要写出这样怪异的 C 程序,逗号运算符无疑是一个好的助手,它的作用是:从左到右依次计算各个表达式的值,并且返回最右边表达式的值。
了解这些内容后,我们将这段代码中的 for
循环展开,等价地写为 while
的形式。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
int a = 10000, b, c = 2800, d, e, f[2801], g;
main() {
for (int i = 0; i < c; i++) {
f[i] = a / 5;
}
while (c != 0) {
d = 0;
g = c * 2;
b = c;
while (1) {
d += f[b] * a;
g--;
f[b] = d % g;
d /= g;
g--;
b--;
if (b == 0) break;
d *= b;
}
c -= 14;
printf("%.4d", e + d / a);
e = d % a;
}
}