65.9K
CodeProject 正在变化。 阅读更多。
Home

通过无穷序列计算 PI 的值

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (22投票s)

2014 年 9 月 3 日

CPOL

4分钟阅读

viewsIcon

148934

downloadIcon

223

使用双精度和任意精度通过无限级数计算 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

注意:测试结果不具有决定性,因为它们没有采用适当的技术进行。此外,多个因素会产生影响,例如编译器、算法、计算机等。

结论

就是这样了!

我将结论留给您在检查上表时得出。真正的目的是享受这些惊人的公式!

希望这有帮助。 欢迎提出问题和评论。

在此处下载源代码

再见..

© . All rights reserved.