求π的值

GitHub跳转原题关系图返回列表

用格雷戈里级数在 x=1/√3 处逐项累加 arctan:分子每步乘 -x² 递推、分母取奇数,整项绝对值首次小于 1e-6 时停止,结果乘 6 输出。

OJ: roj

题目 ID: 1156

难度:入门

标签:入门数学浮点数python

创建: 2026-09-29 21:15

更新: 2026-10-05 03:50

题目描述

利用 \arctanx(x)=x−x33+x55−x77+⋯\arctanx(x) = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \cdots 和恒等式 π=6\arctanx(13)\pi = 6\arctanx(\frac{1}{\sqrt 3}),逐项累加级数求 \arctanx(13)\arctanx(\frac{1}{\sqrt 3}):当最后一项的绝对值小于 10−610^{-6} 时停止,把部分和乘 66 得到 π\pi 的近似值。

  • 输入:无。
  • 输出:π\pi 的值,保留到小数点后 1010 位。

思路

相邻两项的分子比值恒为 −x2-x^2,一个乘法同时完成升幂和变号;分母从 11 起每次加 22。停止条件要比较含分母系数的整项 ∣x2k+12k+1∣\left|\frac{x^{2k+1}}{2k+1}\right|(而非分子),首次小于 10−610^{-6} 的那一项不再累加,最后乘 66 输出 1010 位小数。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 21:15
# update_at: 2026-09-29 21:15

import math

EPS = 1e-6  # 最后一项绝对值小于该阈值就停止累加


def arctanx(x: float) -> float:
    """交错级数求 arctan(x):逐项累加,直到下一项绝对值 < EPS。"""
    term = x  # 当前项 x^(2k+1),由上一项乘 -x^2 递推
    total = 0.0
    for i in range(1, 10**9, 2):
        if abs(term / i) < EPS:  # 该项已小于阈值,成为"最后一项",不再累加
            break
        total += term / i
        term *= -x * x  # 分子乘 -x² 得到下一项
    return total


def solve() -> None:
    print(f"{6 * arctanx(1 / math.sqrt(3)):.10f}")


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 03:50
 * update_at: 2026-10-05 03:50
 */
// main.cpp:用格雷戈里级数在 x=1/sqrt(3) 处求 arctan(x),乘 6 得 π 的近似值。

#include <cstdio>
#include <cmath>

typedef long long ll;

const double EPS = 1e-6; // 最后一项绝对值小于该阈值就停止累加

// 用交错级数求 arctan(x):分子每步乘 -x^2 递推,分母取奇数
double arctanx(double x) {
    double term = x;   // 当前项的分子 x^(2k+1),符号并入因子 -x^2
    double total = 0;  // 部分和
    double up = -x * x; // 相邻两项分子的比值 -x^2
    for (ll i = 1; ; i += 2) {
        if (fabs(term / i) < EPS) // 整项(含分母系数)小于阈值,停止
            break;
        total += term / i;
        term *= up; // 下一项分子:升幂同时变号
    }
    return total;
}

int main() {
    printf("%.10f\n", 6 * arctanx(1 / sqrt(3.0)));
    return 0;
}