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

后端 未结 23 1645
自闭症患者
自闭症患者 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 00:58

    Use the Machin-like formula

    176 * arctan (1/57) + 28 * arctan (1/239) - 48 * arctan (1/682) + 96 * arctan(1/12943) 
    
    [; \left( 176 \arctan \frac{1}{57} + 28 \arctan \frac{1}{239} - 48 \arctan \frac{1}{682} + 96 \arctan \frac{1}{12943}\right) ;], for you TeX the World people.
    

    Implemented in Scheme, for instance:

    (+ (- (+ (* 176 (atan (/ 1 57))) (* 28 (atan (/ 1 239)))) (* 48 (atan (/ 1 682)))) (* 96 (atan (/ 1 12943))))

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

    The Chudnovsky algorithm is pretty fast if you don't mind performing a square root and a couple inverses. It converges to double precision in just 2 iterations.

    /*
        Chudnovsky algorithm for computing PI
    */
    
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    double calc_PI(int K=2) {
    
        static const int A = 545140134;
        static const int B = 13591409;
        static const int D = 640320;
    
        const double ID3 = 1./ (double(D)*double(D)*double(D));
    
        double sum = 0.;
        double b   = sqrt(ID3);
        long long int p = 1;
        long long int a = B;
    
        sum += double(p) * double(a)* b;
    
        // 2 iterations enough for double convergence
        for (int k=1; k<K; ++k) {
            // A*k + B
            a += A;
            // update denominator
            b *= ID3;
            // p = (-1)^k 6k! / 3k! k!^3
            p *= (6*k)*(6*k-1)*(6*k-2)*(6*k-3)*(6*k-4)*(6*k-5);
            p /= (3*k)*(3*k-1)*(3*k-2) * k*k*k;
            p = -p;
    
            sum += double(p) * double(a)* b;
        }
    
        return 1./(12*sum);
    }
    
    int main() {
    
        cout.precision(16);
        cout.setf(ios::fixed);
    
        for (int k=1; k<=5; ++k) cout << "k = " << k << "   PI = " << calc_PI(k) << endl;
    
        return 0;
    }
    

    Results:

    k = 1   PI = 3.1415926535897341
    k = 2   PI = 3.1415926535897931
    k = 3   PI = 3.1415926535897931
    k = 4   PI = 3.1415926535897931
    k = 5   PI = 3.1415926535897931
    
    0 讨论(0)
  • 2020-11-28 01:02

    Here's a general description of a technique for calculating pi that I learnt in high school.

    I only share this because I think it is simple enough that anyone can remember it, indefinitely, plus it teaches you the concept of "Monte-Carlo" methods -- which are statistical methods of arriving at answers that don't immediately appear to be deducible through random processes.

    Draw a square, and inscribe a quadrant (one quarter of a semi-circle) inside that square (a quadrant with radius equal to the side of the square, so it fills as much of the square as possible)

    Now throw a dart at the square, and record where it lands -- that is, choose a random point anywhere inside the square. Of course, it landed inside the square, but is it inside the semi-circle? Record this fact.

    Repeat this process many times -- and you will find there is a ratio of the number of points inside the semi-circle versus the total number thrown, call this ratio x.

    Since the area of the square is r times r, you can deduce that the area of the semi circle is x times r times r (that is, x times r squared). Hence x times 4 will give you pi.

    This is not a quick method to use. But it's a nice example of a Monte Carlo method. And if you look around, you may find that many problems otherwise outside your computational skills can be solved by such methods.

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

    There's actually a whole book dedicated (amongst other things) to fast methods for the computation of \pi: 'Pi and the AGM', by Jonathan and Peter Borwein (available on Amazon).

    I studied the AGM and related algorithms quite a bit: it's quite interesting (though sometimes non-trivial).

    Note that to implement most modern algorithms to compute \pi, you will need a multiprecision arithmetic library (GMP is quite a good choice, though it's been a while since I last used it).

    The time-complexity of the best algorithms is in O(M(n)log(n)), where M(n) is the time-complexity for the multiplication of two n-bit integers (M(n)=O(n log(n) log(log(n))) using FFT-based algorithms, which are usually needed when computing digits of \pi, and such an algorithm is implemented in GMP).

    Note that even though the mathematics behind the algorithms might not be trivial, the algorithms themselves are usually a few lines of pseudo-code, and their implementation is usually very straightforward (if you chose not to write your own multiprecision arithmetic :-) ).

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

    Better Approach

    To get the output of standard constants like pi or the standard concepts, we should first go with the builtins methods available in the language that you are using. It will return a value in the fastest and best way. I am using python to run the fastest way to get the value of pi.

    • pi variable of the math library. The math library stores the variable pi as a constant.

    math_pi.py

    import math
    print math.pi
    

    Run the script with time utility of linux /usr/bin/time -v python math_pi.py

    Output:

    Command being timed: "python math_pi.py"
    User time (seconds): 0.01
    System time (seconds): 0.01
    Percent of CPU this job got: 91%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
    
    • Use arc cos method of math

    acos_pi.py

    import math
    print math.acos(-1)
    

    Run the script with time utility of linux /usr/bin/time -v python acos_pi.py

    Output:

    Command being timed: "python acos_pi.py"
    User time (seconds): 0.02
    System time (seconds): 0.01
    Percent of CPU this job got: 94%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
    
    • use BBP formula

    bbp_pi.py

    from decimal import Decimal, getcontext
    getcontext().prec=100
    print sum(1/Decimal(16)**k * 
              (Decimal(4)/(8*k+1) - 
               Decimal(2)/(8*k+4) - 
               Decimal(1)/(8*k+5) -
               Decimal(1)/(8*k+6)) for k in range(100))
    

    Run the script with time utility of linux /usr/bin/time -v python bbp_pi.py

    Output:

    Command being timed: "python c.py"
    User time (seconds): 0.05
    System time (seconds): 0.01
    Percent of CPU this job got: 98%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.06
    

    So the best way is to use builtin methods provided by the language because they are the fastest and best to get the output. In python use math.pi

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

    Basically the C version of paperclip optimizer's answer, and much more simpilified:

    #include <stdio.h>
    #include <math.h>
    
    double calc_PI(int K) {
        static const int A = 545140134;
        static const int B = 13591409;
        static const int D = 640320;
        const double ID3 = 1.0 / ((double) D * (double) D * (double) D);
        double sum = 0.0;
        double b = sqrt(ID3);
        long long int p = 1;
        long long int a = B;
        sum += (double) p * (double) a * b;
        for (int k = 1; k < K; ++k) {
            a += A;
            b *= ID3;
            p *= (6 * k) * (6 * k - 1) * (6 * k - 2) * (6 * k - 3) * (6 * k - 4) * (6 * k - 5);
            p /= (3 * k) * (3 * k - 1) * (3 * k - 2) * k * k * k;
            p = -p;
            sum += (double) p * (double) a * b;
        }
        return 1.0 / (12 * sum);
    }
    
    int main() {
        for (int k = 1; k <= 5; ++k) {
            printf("k = %i, PI = %.16f\n", k, calc_PI(k));
        }
    }
    

    But for more simplification, this algorithm takes Chudnovsky's formula, which I can fully simplify if you don't really understand the code.

    Summary: We will get a number from 1 to 5 and add it in to a function we will use to get PI. Then 3 numbers are given to you: 545140134 (A), 13591409 (B), 640320 (D). Then we will use D as a double multiplying itself 3 times into another double (ID3). We will then take the square root of ID3 into another double (b) and assign 2 numbers: 1 (p), the value of B (a). Take note that C is case-insensitive. Then a double (sum) will be created by multiplying the value's of p, a and b, all in doubles. Then a loop up until the number given for the function will start and add up A's value to a, b's value gets multiplied by ID3, p's value will be multiplied by multiple values that I hope you can understand and also gets divided by multiple values as well. The sum will add up by p, a and b once again and the loop will repeat until the value of the loop's number is greater or equal to 5. Later, the sum is multiplied by 12 and returned by the function giving us the result of PI.

    Okay, that was long, but I guess you will understand it...

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