摘要:本文是PTA编程题"计算圆周率"的题解,涵盖题目描述、输入输出格式及C++语言实现,展示无穷级数递推迭代与循环控制方法。
题目描述
根据下面关系式,求圆周率的值,直到最后一项的值小于给定阈值。
关系式:
π/2 = 1 + 1/3 + 2!/(3×5) + 3!/(3×5×7) + ... + n!/(3×5×7×...×(2n+1)) + ...输入格式:
输入在一行中给出小于1的阈值。
输出格式:
在一行中输出满足阈值条件的近似圆周率,输出到小数点后6位。
输入样例:
0.01输出样例:
3.132157解题思路
核心问题分析
本题是一个典型的无穷级数求和问题。核心任务是根据给定的无穷级数公式计算π/2的近似值,当某一项的值小于给定阈值时停止累加,最后乘以2得到圆周率π。关键在于:
- 理解级数通项的递推关系,避免重复计算阶乘和乘积
- 控制循环终止条件:最后一项的值 < 阈值时停止
算法原理说明
观察级数通项的规律,使用递推迭代法高效计算每一项:
设第n项为 aₙ,则:
- a₀ = 1(第0项,对应 n=0)
- a₁ = 1/3(第1项,对应 n=1)
- a₂ = 2!/(3×5) = (1×2)/(3×5)(第2项,对应 n=2)
- a₃ = 3!/(3×5×7) = (1×2×3)/(3×5×7)(第3项,对应 n=3)
递推关系推导:
aₙ / aₙ₋₁ = [n!/(3×5×…×(2n+1))] / [(n-1)!/(3×5×…×(2n-1))]
= n / (2n + 1)
因此:aₙ = aₙ₋₁ × n / (2n + 1)
这样每一项可以由前一项递推得到,无需每次重新计算阶乘和连乘,时间复杂度O(k),k为迭代次数。
具体计算步骤
- 输入阈值 threshold(小于1的正数)
- 初始化:
- sum = 1.0(累加和,已加入第0项 a₀ = 1)
- term = 1.0(当前项,初始为 a₀)
- n = 1(下一项的序号)
- 循环迭代:
- 计算新项:term = term × n / (2n + 1)(即 aₙ = aₙ₋₁ × n/(2n+1))
- 累加到总和:sum = sum + term
- 判断:若 term < threshold → 跳出循环(停止累加)
- 否则:n = n + 1,继续迭代
- 计算圆周率:pi = 2.0 × sum
- 输出pi,保留6位小数
验证样例(threshold = 0.01):
- a₀ = 1,sum = 1
- n=1: a₁ = 1 × 1/3 = 0.33333,sum = 1.33333,0.33333 > 0.01 → 继续
- n=2: a₂ = 0.33333 × 2/5 = 0.13333,sum = 1.46666,0.13333 > 0.01 → 继续
- n=3: a₃ = 0.13333 × 3/7 ≈ 0.05714,sum ≈ 1.52381,0.05714 > 0.01 → 继续
- n=4: a₄ = 0.05714 × 4/9 ≈ 0.02540,sum ≈ 1.54921,0.02540 > 0.01 → 继续
- n=5: a₅ = 0.02540 × 5/11 ≈ 0.01155,sum ≈ 1.56076,0.01155 > 0.01 → 继续
- n=6: a₆ = 0.01155 × 6/13 ≈ 0.00533,sum ≈ 1.56609,0.00533 < 0.01 → 停止
- pi = 2 × 1.56609 ≈ 3.13218 → 接近样例输出3.132157 ✓
代码部分实现
#include<iostream>#include<cstdio>usingnamespacestd;intmain(void){doublethreshold;cin>>threshold;doublesum=1.0;doubleterm=1.0;intn=1;while(1){term*=(double)n/(2*n+1);sum+=term;if(term<threshold){break;}n++;}doublepi=2.0*sum;printf("%.6f\n",pi);return0;}代码流程说明
头文件引入与命名空间声明
#include <iostream>:引入标准输入输出流头文件#include <cstdio>:引入C标准I/O头文件,提供printf格式化输出using namespace std;:使用std命名空间
主函数入口
int main(void):程序主函数入口
数据输入
double threshold;:定义阈值变量(双精度浮点型)cin >> threshold;:读取用户输入的阈值
变量初始化
double sum = 1.0;:累加和初始化,已包含第0项 a₀ = 1double term = 1.0;:当前项初始化,初始值为第0项 a₀ = 1int n = 1;:下一项的序号,从1开始(因为a₀已处理)
while循环递推累加
while (1):无限循环,由内部条件break控制退出- 循环体内:
term *= (double)n / (2 * n + 1);- 递推计算下一项:term_new = term_old × n / (2n + 1)
- (double)n 将整型n强制转换为浮点型,确保浮点除法
sum += term;:将新计算的项累加到总和sum中if (term < threshold):判断当前项是否小于阈值- 条件为真 →
break;跳出循环,停止累加
- 条件为真 →
n++;:项序号n加1,准备计算下一项
计算圆周率并输出
double pi = 2.0 * sum;:由关系式 π/2 = sum,得 π = 2 × sumprintf("%.6f\n", pi);:格式化输出pi- %.6f:浮点数保留6位小数
- \n:输出换行符
程序结束
return 0;:返回0,程序正常退出