예제 #1
0
        private static Series.PQ ArctanOfInverse(mpz digits, mpz x, bool isHyperbolic)
        {
            if (digits == null)
            {
                throw new ArgumentNullException("digits");
            }
            if (digits <= 0)
            {
                throw new ArgumentOutOfRangeException("digits");
            }
            if (x == null)
            {
                throw new ArgumentNullException("x");
            }
            if (x <= 1)
            {
                throw new ArgumentOutOfRangeException("x");
            }

            // http://numbers.computation.free.fr/Constants/Algorithms/splitting.html
            Func <mpz, mpz, Series.PQT> directlyCompute = (a, b) =>
            {
                var t = 2 * a + 3;
                var q = t * x.Square();
                var p = (!isHyperbolic && a.IsEven()) ? mpz.NegativeOne : mpz.One;
                return(new Series.PQT {
                    P = p, Q = q, T = t
                });
            };
            Func <Series.PQT, Series.PQT, Series.PQT> recursivelyCombine = (am, mb) => new Series.PQT {
                P = mb.Q * am.P + am.T * mb.P, Q = am.Q * mb.Q, T = am.T * mb.T
            };

            // How many terms to compute

            /*
             *         x^(2k+1) > 10^digits
             * => (2k+1) log(x) > digits * log(10)
             * =>        2k + 1 > digits * log(10) / log(x)
             * =>            2k > digits * log(10) / log(x)
             * =>             k > [digits * log(10) / log(x)] / 2
             */
            var n = (digits.ToMpf() * Math.Log(10, (double)x) / 2).ToMpz() + _ARCTAN_OF_INVERSE_NUMBER_OF_TERMS_SURCHARGE;

            // Calclate P(0,N), Q(0,N) and T(0,N)
            var pqt = Series.BinarySplitting(0, n, directlyCompute, recursivelyCombine);

            return(new Series.PQ {
                P = pqt.P + pqt.Q, Q = x * pqt.Q
            });
        }
예제 #2
0
        /*
         * Compute int(pi * 10^digits)
         *
         * This is done using Chudnovsky's series with binary splitting
         */
        public static mpz PiZ(mpz digits)
        {
            if (digits == null)
            {
                throw new ArgumentNullException("digits");
            }
            if (digits <= 0)
            {
                throw new ArgumentOutOfRangeException("digits");
            }

            const long C          = 640320;
            const long C3_OVER_24 = C * C * C / 24;

            /*
             * Source: http://www.craig-wood.com/nick/articles/pi-chudnovsky/
             *
             * Computes the terms for binary splitting the Chudnovsky infinite series
             *
             * a(a) = +/- (13591409 + 545140134*a)
             * p(a) = (6*a-5)*(2*a-1)*(6*a-1)
             * b(a) = 1
             * q(a) = a*a*a*C3_OVER_24
             */
            Func <mpz, mpz, Series.PQT> directlyCompute = (a, b) =>
            {
                mpz Pab, Qab;
                if (a == 0)
                {
                    Pab = Qab = mpz.One;
                }
                else
                {
                    var a2 = a << 1;
                    var a6 = a2 * 3;
                    Pab = (a6 - 5) * (a2 - 1) * (a6 - 1);
                    Qab = a.Power(3U) * C3_OVER_24;
                }

                // t(a) = p(a) * a(a)
                var Tab = Pab * (13591409 + 545140134 * a);
                if (a.IsOdd())
                {
                    Tab = -Tab;
                }

                return(new Series.PQT {
                    P = Pab, Q = Qab, T = Tab
                });
            };
            Func <Series.PQT, Series.PQT, Series.PQT> recursivelyCombine = (am, mb) => new Series.PQT
            {
                P = am.P * mb.P,
                Q = am.Q * mb.Q,
                T = mb.Q * am.T + am.P * mb.T
            };

            // How many terms to compute
            var digitsPerTerm = Math.Log10(C3_OVER_24 / 6 / 2 / 6);
            var n             = (digits.ToMpf() / digitsPerTerm).ToMpz() + _PI_NUMBER_OF_TERMS_SURCHARGE;

            // Calculate P(0, N), Q(0, N) and T(0, N)
            var pqt        = Series.BinarySplitting(0, n, directlyCompute, recursivelyCombine);
            var oneSquared = mpz.Ten.Power(digits << 1);
            var sqrtC      = (10005 * oneSquared).Sqrt();

            return((pqt.Q * 426880 * sqrtC) / pqt.T);
        }