通过无穷序列计算 PI 的值






4.71/5 (22投票s)
使用双精度和任意精度通过无限级数计算 PI 近似的迭代算法
“任何圆的周长都大于其直径的三倍,而这个多余的部分小于直径的七分之一,但大于其七十一分之一的十倍。” - 阿基米德
引言
用 PI 的前 50 位小数来介绍 PI:
3.1415926535897932384626433832795028841971693993751
它是一个无理数和超越数。它的小数部分是无限连续的数字,它们的计算已成为计算数学的经典问题。这是因为它们的生成需要大量的处理能力,因此需要更有效的算法。
纵观历史,人们发现可以通过无穷级数以一定的“精度”获得 PI 的数字,这正是我们将在本文中做的。
然而,我们警告说,这里提出的算法的实际用途值得怀疑,因为在大多数情况下,计算 PI 到小数点后六位就足够了,因此一个更有效的算法如下:
function double PI(): {
return (3.141593);
}
一点历史
传统上,我们将 PI 定义为周长与其直径之比。然而,历史上并非总是如此。
众所周知,这个无理数是几何学家们随着时间的推移计算出来的,作为至少 4 种关系的比例常数,顺序不一定如此:
- 圆的周长与其直径之间;
- 圆的面积与直径的平方之间;
- 球的表面积与直径的平方之间;
- 球的体积与直径的立方之间;
最早已知的关于 PI 的书面记载来自公元前 2000 年左右的巴比伦。从那时起,他们的近似值经历了多次转变,直到今天在计算机的帮助下获得了数十亿位数字。
历史上,PI 的最佳近似值之一,而且有趣的是也是最古老的近似值之一,是中国数学家祖冲之(公元 450 年)使用的,他将 PI 关联为介于 3.1415926 和 3.1415927 之间的“某物”。
PI 的计算因无穷级数技术的发展而彻底改变,特别是 16 世纪和 17 世纪欧洲数学家的贡献。
无穷级数是无穷序列项的和(或积)。这种方法最早于公元 1400 年至 1500 年之间在印度被发现。
现在让我们来看看该领域的主要发现
韦达级数
在欧洲发现的第一个无穷序列是无穷积,由法国数学家 弗朗索瓦·韦达 于 1593 年发现:
沃利斯级数
在欧洲由 约翰·沃利斯 于 1655 年发现的第二个无穷序列也是一个无穷积:
莱布尼茨级数
印度数学家 萨格拉马的马达瓦 提出了一个级数,该级数于 1671 年被苏格兰数学家 詹姆斯·格雷戈里 重新发现,并于 1674 年被 莱布尼茨 重新发现:
尼拉坎塔级数
由 尼拉坎塔 在 15 世纪发表的 PI 的无穷级数是:
背景
为了测试这里提出的算法,我建议使用以下 IDE: Orwell Dev-C++
使用代码
在将此处提出的算法用于生产环境之前,有必要验证输入数据,因为基本数据类型的取值范围有限,且依赖于硬件。“double”类型提供 16-20 位的精度。
最后一个算法使用任意精度(大数)的数据类型,因此可以获得更多位小数的 PI 数(100 位,可配置)。
然而,我们的目的更为谦虚。我们想获得 PI 的 8 位小数,然后对这些方法进行比较。
我们开始算法!
1) 韦达级数 - 双精度
// Approximation of the number PI through the Viete's series
// Language: C
// Author: Jose Cintra (jose.cintra@html-apps.info)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
double n, i, j; // Number of iterations and control variables
double f; // factor that repeats
double pi = 1;
printf("Approximation of the number PI through the Viete's series\n");
printf("\nEnter the number of iterations: ");
scanf("%lf",&n);
printf("\nPlease wait. Running...\n");
for(i = n; i > 1; i--) {
f = 2;
for(j = 1; j < i; j++){
f = 2 + sqrt(f);
}
f = sqrt(f);
pi = pi * f / 2;
}
pi *= sqrt(2) / 2;
pi = 2 / pi;
printf("\nAproximated value of PI = %1.16lf\n", pi);
}
2) 沃利斯级数 - 双精度
// Approximation of the number pi through the Wallis's series
// Language: C
// Author: Jose Cintra (jose.cintra@html-apps.info)
#include <stdio.h>
#include <stdlib.h>
main() {
double n, i // Number of iterations and control variable
double pi = 4;
printf("Approximation of the number pi through the Wallis's series\n");
printf("\nEnter the number of iterations: ");
scanf("%lf",&n);
printf("\nPlease wait. Running...\n");
for(i = 3; i <= (n + 2); i+=2)
pi = pi * ((i - 1) / i) * (( i + 1) / i);
printf("\nAproximated value of PI = %1.16lf\n", pi);
}
3) 莱布尼茨级数 - 双精度
// Approximation of the number PI through the Leibniz's series
// Language: C
// Author: Jose Cintra (jose.cintra@html-apps.info)
#include <stdio.h>
#include <stdlib.h>
main() {
double n, i; // Number of iterations and control variable
double s = 1; //Signal for the next iteration
double pi = 0;
printf("Approximation of the number PI through the Leibniz's series\n");
printf("\nEnter the number of iterations: ");
scanf("%lf",&n);
printf("\nPlease wait. Running...\n");
for(i = 1; i <= (n * 2); i += 2){
pi = pi + s * (4 / i);
s = -s;
}
printf("\nAproximated value of PI = %1.16lf\n", pi);
}
4) 尼拉坎塔级数 - 双精度
// Approximation of the number pi through the Nilakantha's series
// Language: C
// Author: Jose Cintra (jose.cintra@html-apps.info)
#include <stdio.h>
#include <stdlib.h>
main() {
double n, i; // Number of iterations and control variable
double s = 1; //Signal for the next operation
double pi = 3;
printf("Approximation of the number PI through the sequence of the Nilakantha's series\n");
printf("\nEnter the number of iterations: ");
scanf("%lf",&n);
printf("\nPlease wait. Running...\n");
for(i = 2; i <= n*2; i += 2){
pi = pi + s * (4 / (i * (i + 1) * (i + 2)));
s = -s;
}
printf("\nAproximated value of PI = %1.16lf\n", pi);
}
5) 尼拉坎塔级数 - 任意精度
# Approximation of the number PI through the Nilakantha's series
# Arbitrary precision
# Language: Python
# Author: Jose Cintra (jose.cintra@html-apps.info)
from decimal import *
getcontext().prec = 100
s = Decimal(1); #Signal for the next operation
pi = Decimal(3);
print ("Approximation of the number PI through the Nilakantha's series\n")
n = input("Enter the number of iterations: ")
print("\nPlease wait. Running...\n");
for i in range (2, n * 2, 2):
pi = pi + s * (Decimal(4) / (Decimal(i) * (Decimal(i) + Decimal(1)) * (Decimal(i) + Decimal(2))))
s = -1 * s
print ("Aproximated value of PI :")
print (pi)
结果
下面是使用每种算法计算 pi 到 8 位小数(3.14159265)的测试结果。
编译器:MinGW - GCC 4.8.1 - 64 位
处理器:I3 - 2.10GHz
迭代次数 (n) | 时间(秒) | |
莱布尼茨 | 900000000 | 24.48 |
尼拉坎塔 - 双精度 | 500 | 3.16 |
韦达 | 15 | 2.2 |
沃利斯 | 900000000 | 14.4 |
尼拉坎塔 - 任意精度 | 350 | 3.70 |
注意:测试结果不具有决定性,因为它们没有采用适当的技术进行。此外,多个因素会产生影响,例如编译器、算法、计算机等。
结论
就是这样了!
我将结论留给您在检查上表时得出。真正的目的是享受这些惊人的公式!
希望这有帮助。 欢迎提出问题和评论。
再见..