Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
128 views
in Technique[技术] by (71.8m points)

c# - Specify a starting index for continuation of calculating Pi

This C# code will calculate Pi to whatever length I specify. I want to be able to start at a given index without recalculating to that point. Precision is not a great concern as this is a puzzle project but I do need this code to reproduce the same results over and over. It works fine as is but I haven't been able to figure out how to modify for a starting point.

//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;
        }
    }
question from:https://stackoverflow.com/questions/66065526/specify-a-starting-index-for-continuation-of-calculating-pi

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are using the Machin formula with the Taylor serie expansion for Arctan. It should give you about 1.4 digits of precision for each "cycle" (see here). You can't "shortcut" the calculation of the Taylor serie. You can speed-up a little the program removing the IEnumerable<BigInteger> part and simply returning the nth iteration (the yield instruction has a cost) and by changing the BigInteger.Pow with a fixed multiplication. But the calculation will still be made iteratively. There is no known way for calculating PI with a precision of n digits in O(1) time.

Note that there are algorithms (see the wiki) that converge in a smaller number of cycles, but I'm not sure if they converge in a smaller number of operations (their cycles are much more complex).

An optimized version of the code:

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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...