What is the fastest way to get the value of π?

后端 未结 23 1643
自闭症患者
自闭症患者 2020-11-28 00:33

I\'m looking for the fastest way to obtain the value of π, as a personal challenge. More specifically, I\'m using ways that don\'t involve using #define constan

相关标签:
23条回答
  • 2020-11-28 01:13

    The BBP formula allows you to compute the nth digit - in base 2 (or 16) - without having to even bother with the previous n-1 digits first :)

    0 讨论(0)
  • 2020-11-28 01:13

    Pi is exactly 3! [Prof. Frink (Simpsons)]

    Joke, but here's one in C# (.NET-Framework required).

    using System;
    using System.Text;
    
    class Program {
        static void Main(string[] args) {
            int Digits = 100;
    
            BigNumber x = new BigNumber(Digits);
            BigNumber y = new BigNumber(Digits);
            x.ArcTan(16, 5);
            y.ArcTan(4, 239);
            x.Subtract(y);
            string pi = x.ToString();
            Console.WriteLine(pi);
        }
    }
    
    public class BigNumber {
        private UInt32[] number;
        private int size;
        private int maxDigits;
    
        public BigNumber(int maxDigits) {
            this.maxDigits = maxDigits;
            this.size = (int)Math.Ceiling((float)maxDigits * 0.104) + 2;
            number = new UInt32[size];
        }
        public BigNumber(int maxDigits, UInt32 intPart)
            : this(maxDigits) {
            number[0] = intPart;
            for (int i = 1; i < size; i++) {
                number[i] = 0;
            }
        }
        private void VerifySameSize(BigNumber value) {
            if (Object.ReferenceEquals(this, value))
                throw new Exception("BigNumbers cannot operate on themselves");
            if (value.size != this.size)
                throw new Exception("BigNumbers must have the same size");
        }
    
        public void Add(BigNumber value) {
            VerifySameSize(value);
    
            int index = size - 1;
            while (index >= 0 && value.number[index] == 0)
                index--;
    
            UInt32 carry = 0;
            while (index >= 0) {
                UInt64 result = (UInt64)number[index] +
                                value.number[index] + carry;
                number[index] = (UInt32)result;
                if (result >= 0x100000000U)
                    carry = 1;
                else
                    carry = 0;
                index--;
            }
        }
        public void Subtract(BigNumber value) {
            VerifySameSize(value);
    
            int index = size - 1;
            while (index >= 0 && value.number[index] == 0)
                index--;
    
            UInt32 borrow = 0;
            while (index >= 0) {
                UInt64 result = 0x100000000U + (UInt64)number[index] -
                                value.number[index] - borrow;
                number[index] = (UInt32)result;
                if (result >= 0x100000000U)
                    borrow = 0;
                else
                    borrow = 1;
                index--;
            }
        }
        public void Multiply(UInt32 value) {
            int index = size - 1;
            while (index >= 0 && number[index] == 0)
                index--;
    
            UInt32 carry = 0;
            while (index >= 0) {
                UInt64 result = (UInt64)number[index] * value + carry;
                number[index] = (UInt32)result;
                carry = (UInt32)(result >> 32);
                index--;
            }
        }
        public void Divide(UInt32 value) {
            int index = 0;
            while (index < size && number[index] == 0)
                index++;
    
            UInt32 carry = 0;
            while (index < size) {
                UInt64 result = number[index] + ((UInt64)carry << 32);
                number[index] = (UInt32)(result / (UInt64)value);
                carry = (UInt32)(result % (UInt64)value);
                index++;
            }
        }
        public void Assign(BigNumber value) {
            VerifySameSize(value);
            for (int i = 0; i < size; i++) {
                number[i] = value.number[i];
            }
        }
    
        public override string ToString() {
            BigNumber temp = new BigNumber(maxDigits);
            temp.Assign(this);
    
            StringBuilder sb = new StringBuilder();
            sb.Append(temp.number[0]);
            sb.Append(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);
    
            int digitCount = 0;
            while (digitCount < maxDigits) {
                temp.number[0] = 0;
                temp.Multiply(100000);
                sb.AppendFormat("{0:D5}", temp.number[0]);
                digitCount += 5;
            }
    
            return sb.ToString();
        }
        public bool IsZero() {
            foreach (UInt32 item in number) {
                if (item != 0)
                    return false;
            }
            return true;
        }
    
        public void ArcTan(UInt32 multiplicand, UInt32 reciprocal) {
            BigNumber X = new BigNumber(maxDigits, multiplicand);
            X.Divide(reciprocal);
            reciprocal *= reciprocal;
    
            this.Assign(X);
    
            BigNumber term = new BigNumber(maxDigits);
            UInt32 divisor = 1;
            bool subtractTerm = true;
            while (true) {
                X.Divide(reciprocal);
                term.Assign(X);
                divisor += 2;
                term.Divide(divisor);
                if (term.IsZero())
                    break;
    
                if (subtractTerm)
                    this.Subtract(term);
                else
                    this.Add(term);
                subtractTerm = !subtractTerm;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 01:14

    With doubles:

    4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))
    

    This will be accurate up to 14 decimal places, enough to fill a double (the inaccuracy is probably because the rest of the decimals in the arc tangents are truncated).

    Also Seth, it's 3.141592653589793238463, not 64.

    0 讨论(0)
  • 2020-11-28 01:15

    If you are willing to use an approximation, 355 / 113 is good for 6 decimal digits, and has the added advantage of being usable with integer expressions. That's not as important these days, as "floating point math co-processor" ceased to have any meaning, but it was quite important once.

    0 讨论(0)
  • 2020-11-28 01:17

    This is a "classic" method, very easy to implement. This implementation in python (not the fastest language) does it:

    from math import pi
    from time import time
    
    
    precision = 10**6 # higher value -> higher precision
                      # lower  value -> higher speed
    
    t = time()
    
    calc = 0
    for k in xrange(0, precision):
        calc += ((-1)**k) / (2*k+1.)
    calc *= 4. # this is just a little optimization
    
    t = time()-t
    
    print "Calculated: %.40f" % calc
    print "Constant pi: %.40f" % pi
    print "Difference: %.40f" % abs(calc-pi)
    print "Time elapsed: %s" % repr(t)
    

    You can find more information here.

    Anyway, the fastest way to get a precise as-much-as-you-want value of pi in python is:

    from gmpy import pi
    print pi(3000) # the rule is the same as 
                   # the precision on the previous code
    

    Here is the piece of source for the gmpy pi method, I don't think the code is as useful as the comment in this case:

    static char doc_pi[]="\
    pi(n): returns pi with n bits of precision in an mpf object\n\
    ";
    
    /* This function was originally from netlib, package bmp, by
     * Richard P. Brent. Paulo Cesar Pereira de Andrade converted
     * it to C and used it in his LISP interpreter.
     *
     * Original comments:
     * 
     *   sets mp pi = 3.14159... to the available precision.
     *   uses the gauss-legendre algorithm.
     *   this method requires time o(ln(t)m(t)), so it is slower
     *   than mppi if m(t) = o(t**2), but would be faster for
     *   large t if a faster multiplication algorithm were used
     *   (see comments in mpmul).
     *   for a description of the method, see - multiple-precision
     *   zero-finding and the complexity of elementary function
     *   evaluation (by r. p. brent), in analytic computational
     *   complexity (edited by j. f. traub), academic press, 1976, 151-176.
     *   rounding options not implemented, no guard digits used.
    */
    static PyObject *
    Pygmpy_pi(PyObject *self, PyObject *args)
    {
        PympfObject *pi;
        int precision;
        mpf_t r_i2, r_i3, r_i4;
        mpf_t ix;
    
        ONE_ARG("pi", "i", &precision);
        if(!(pi = Pympf_new(precision))) {
            return NULL;
        }
    
        mpf_set_si(pi->f, 1);
    
        mpf_init(ix);
        mpf_set_ui(ix, 1);
    
        mpf_init2(r_i2, precision);
    
        mpf_init2(r_i3, precision);
        mpf_set_d(r_i3, 0.25);
    
        mpf_init2(r_i4, precision);
        mpf_set_d(r_i4, 0.5);
        mpf_sqrt(r_i4, r_i4);
    
        for (;;) {
            mpf_set(r_i2, pi->f);
            mpf_add(pi->f, pi->f, r_i4);
            mpf_div_ui(pi->f, pi->f, 2);
            mpf_mul(r_i4, r_i2, r_i4);
            mpf_sub(r_i2, pi->f, r_i2);
            mpf_mul(r_i2, r_i2, r_i2);
            mpf_mul(r_i2, r_i2, ix);
            mpf_sub(r_i3, r_i3, r_i2);
            mpf_sqrt(r_i4, r_i4);
            mpf_mul_ui(ix, ix, 2);
            /* Check for convergence */
            if (!(mpf_cmp_si(r_i2, 0) && 
                  mpf_get_prec(r_i2) >= (unsigned)precision)) {
                mpf_mul(pi->f, pi->f, r_i4);
                mpf_div(pi->f, pi->f, r_i3);
                break;
            }
        }
    
        mpf_clear(ix);
        mpf_clear(r_i2);
        mpf_clear(r_i3);
        mpf_clear(r_i4);
    
        return (PyObject*)pi;
    }
    

    EDIT: I had some problems with cut and paste and indentation, you can find the source here.

    0 讨论(0)
提交回复
热议问题