现在的位置: 首页 > 综合 > 正文

求圆周率π的几种方法

2017年08月06日 ⁄ 综合 ⁄ 共 2147字 ⁄ 字号 评论关闭

方法1:概率法求π的近似值。

概率法又称蒙特卡罗法。假设有一个半径为1的圆,则四分之一圆的面积等于1/4π。通过概率法计算出四分之一圆的面积,也就得到了1/4π。具体过程为:利用随机函数产生横坐标x和纵坐标y(两个值在0~1之间),接着判断由这两个随机数构成的点是否位于1/4圆的区域内,若该点位于1/4圆内则进行计数。由于随机函数生成的点坐标有一定的均匀性,当生成的点足够多时,就可得到阴影内和阴影外点的近似均匀分布。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int n, sum = 0;
	double x, y;
	printf("请输入点的数量:");
	scanf("%d", &n);
	srand((unsigned)time(NULL));
	for (int i = 1; i < n; i++)
	{
		x = (double)rand() / RAND_MAX;
		y = (double)rand() / RAND_MAX;
		if (x * x + y * y <= 1)
		{
			sum += 1;
		}
	}
	printf("PI = %f\n", (double)4 * sum / n);
	
	return 0;
}

方法2:割圆法求π的近似值。

割圆法利用圆的内接多边形来逼近圆的周长。通过不断地将内接多边形进行切割划分,使其无限逼近圆周,则可得到精确度更高的π值。

#include <stdio.h>
#include <math.h>

int main(void)
{
	double x = 1, PI;
	int count, n = 0;
	int s = 6;					//初始内接圆边数
	printf("请输入割圆次数:");
	scanf("%d", &count);
	
	while (n <= count)
	{
		printf("第%d次割圆,内接正%d边形:", n, s);
		PI = s * x / 2;
		printf("PI = %.12f\n", PI);
		x = sqrt(2 - sqrt(4 - x * x));
		s *= 2;
		n += 1;
	}
	
	return 0;
}

方法3:公式法求π的近似值。

利用以下公式可方便计算π的近似值。π=2+2/3+2/3×2/5+2/3×2/5×3/7+2/3×2/5×3/7×4/9+⋯

#include <stdio.h>

int main(void)
{
	double temp = 2, PI = 2;
	int a = 1, b = 3;		//a为分子,b为分母

	while (temp > 1e-20)
	{
		temp *= (double)a / b;
		PI += temp;
		a += 1;
		b += 2;
	}
	printf("PI = %.12f\n", PI);

	return 0;
}

注意:程序中需要根据精度要求结束循环。

方法4:计算任意位数的π。

方法1至方法3计算出来的π值,由于使用单变量保存结果,限于计算机硬件对变量的表示范围有限,因此,最多只能计算出π值小数点后十多位。为了提高精度,可定义数组来逐位保存无限循环小数,基本思路仍然是利用方法3的公式法。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	char *temp, *pi;
	int decLen;					//小数位数
	int a = 1, b = 3;			//分子分母
	int result, i, carry;
	int count = 0, flag = 1;	//计算次数
	
	printf("请输入π的小数位数:");
	scanf("%d", &decLen);
	decLen += 2;

	if (!(temp = (char *)malloc(sizeof(char) * decLen)))
	{
		return 0;
	}
	if (!(pi = (char *)malloc(sizeof(char) * decLen)))
	{
		return 0;
	}

	for (i = 0; i < decLen; i++)
	{
		*(pi + i) = 0;
		*(temp + i) = 0;
	}

	pi[1] = 2;						//初始化值
	temp[1] = 2;
	
	while (flag && ++count < 1e6)
	{
		carry = 0;
		for (i = decLen - 1; i >= 0 ; i--)
		{
			result = temp[i] * a + carry;
			temp[i] = result % 10;
			carry = result / 10;
		}
		
		carry = 0;
		for (i = 0; i < decLen; i++)
		{
			result = temp[i] + carry * 10;
			temp[i] = result / b;
			carry = result % b;
		}
		
		flag = 0;
		for (i = decLen - 1; i > 0; i--)
		{
			result = pi[i] + temp[i];
			pi[i] = result % 10;
			pi[i - 1] += result / 10;
			flag |= temp[i];
		}

		a += 1;
		b += 2;
	}

	printf("计算了:%d次\n", count);
	printf("PI = %d.", pi[1]);		//输出个位和小数点
	for (i = 2; i < decLen; i++)
	{
		if ((i > 2) && (i - 2) % 10 == 0)
		{
			printf(" ");
		}
		if ((i > 2) && (i - 2) % 50 == 0)
		{
			printf("\n");
		}

		printf("%d", pi[i]);
	}
	printf("\n");

	return 0;
}

注意:终止循环的条件是:数组temp中全部为0,即已经没有余数需要处理。如果数组中元素一直不为0,则还需要设置另外的条件来终止循环,如规定循环处理次数。

抱歉!评论已关闭.