指定继续计算 Pi 的起始索引

Specify a starting index for continuation of calculating Pi

此 C# 代码将计算 Pi 到我指定的任何长度。我希望能够从给定的索引开始,而无需重新计算到那个点。精度不是一个大问题,因为这是一个拼图项目,但我确实需要这段代码来一遍又一遍地重现相同的结果。它按原样运行良好,但我一直无法弄清楚如何修改起点。

//Looking to pass BigInteger to specify a starting index for continuation of calculating Pi

    public static BigInteger GetPi(int digits, int iterations)
    {
        return 16 * ArcTan1OverX(5, digits).ElementAt(iterations)
            - 4 * ArcTan1OverX(239, digits).ElementAt(iterations);
    }

    public static IEnumerable<BigInteger> ArcTan1OverX(int x, int digits)
    {
        var mag = BigInteger.Pow(10, digits);
        var sum = BigInteger.Zero;
        bool sign = true;
        for (int i = 1; true; i += 2)
        {
            var cur = mag / (BigInteger.Pow(x, i) * i);
            if (sign)
            {
                sum += cur;
            }
            else
            {
                sum -= cur;
            }
            yield return sum;
            sign = !sign;
        }
    }

您正在使用 Machin formula with the Taylor serie expansion for Arctan. It should give you about 1.4 digits of precision for each "cycle" (see here)。你不能“捷径”计算泰勒级数。您可以稍微加快程序速度,删除 IEnumerable<BigInteger> 部分并简单地返回第 n 次迭代(yield 指令有成本)并通过使用固定乘法更改 BigInteger.Pow 。但计算仍将迭代进行。没有已知的方法可以在 O(1) 时间内计算精度为 n 位的 PI。

请注意,有些算法(请参阅 wiki)在较少的循环次数中收敛,但我不确定它们是否在较少的操作次数中收敛(它们的循环要复杂得多).

代码的优化版本:

public static BigInteger GetPi2(int digits, int iterations)
{
    return 16 * ArcTan1OverX2(5, digits, iterations)
        - 4 * ArcTan1OverX2(239, digits, iterations);
}

public static BigInteger ArcTan1OverX2(int x, int digits, int iterations)
{
    var mag = BigInteger.Pow(10, digits);
    var sum = BigInteger.Zero;
    bool sign = true;

    int imax = 1 + (2 * iterations);

    int xsquared = x * x;
    BigInteger pow = x;

    for (int i = 1; i <= imax; i += 2)
    {
        if (i != 1)
        {
            pow *= xsquared;
        }

        var cur = mag / (pow * i);

        if (sign)
        {
            sum += cur;
        }
        else
        {
            sum -= cur;
        }

        sign = !sign;
    }

    return sum;
}