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
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))))
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
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.
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 :-) ).
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.
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
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
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
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 double
s. 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...