Q: why ... reach precision upto 15th decimal place?
A: To display 15 decimal places after the decimal point use format "%0.15f"
. To calculate 15 decimal places of convergence, at a minimum, n
will need to be very large.
As mentioned by @user3386109, "error in the result is bounded by 1 / (2n+1)", so about 5e14 iterations will be needed. (Rough estimate: 10 days on my PC.) As typical double
has a precision of about 1 part in pow(2,53) or 1 in 9e15, the limits of double
calculation are being reached. The below code compares the order of calculation to reduce error, but at best, the error will still be at least 0.5 parts in 9e15.
As the terms of the series oscillate about the limit, when stopping after n
iterations, a final iteration of 1/2 the next iteration could be added. this would gain about 1 bit of accuracy.
As others have mentioned, other methods exist to calculate π that converge faster.
Updated per the good observation by @user3386109.
In summing the terms, code can sum them in various orders. The 2 below methods illustrate that a modestly more stable result is achieved earlier when summing the small terms together first. I`d expect at best only a 1 or 2 bit better answer.
This was re-done using float
as the small improvement does not show up until the last few bits are stable. With double
and this slowly convergent series, that would take too long.
//Leibniz formula for pi/4
typedef float fp;
fp LeibnizForward(unsigned n) {
volatile fp sum = 0.0;
fp sign = 1.0;
unsigned i = 1;
while (n-- > 0) {
sum += sign / i;
sign = -sign;
i = (i + 2);
}
return sum;
}
fp LeibnizReverse(unsigned n) {
volatile fp sum = 0.0;
fp sign = 1.0;
unsigned i = 2 * n - 1;
if (n % 2 == 0)
sign = -sign;
while (n-- > 0) {
sum += sign / i;
sign = -sign;
i = (i - 2);
}
return sum;
}
void PiTest(unsigned n) {
printf("%u\n", n);
static const fp pic = 3.1415926535897932384626433832795;
const char *format = "%s %0.9f\n";
printf(format, "pi-", nextafterf(pic,0));
printf(format, "pi ", pic);
printf(format, "pi+", nextafterf(pic,4));
fp pif = LeibnizForward(n) * 4;
printf(format, "pif", pif);
fflush(stdout);
fp pir = LeibnizReverse(n) * 4;
printf(format, "pir", pir);
fflush(stdout);
}
int main(void) {
PiTest(0);
PiTest(1);
PiTest(10);
PiTest(100);
PiTest(1000);
PiTest(10000);
PiTest(100000);
PiTest(1000000);
PiTest(10000000);
PiTest(100000000);
return 0;
}
0
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 0.000000000
pir 0.000000000
1
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 4.000000000
pir 4.000000000
10
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.041839600
pir 3.041839600
25
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.181576490
pir 3.181576729
100
pi- 3.141592503
pi 3.141592741
pi+ 3.141592979
pif 3.131592512
pir 3.131592751
1000
pi- 3.14 1592503
pi 3.14 1592741
pi+ 3.14 1592979
pif 3.14 0592575
pir 3.14 0592575
10000
pi- 3.141 592503
pi 3.141 592741
pi+ 3.141 592979
pif 3.141 498566
pir 3.141 492605
100000
pi- 3.1415 92503
pi 3.1415 92741
pi+ 3.1415 92979
pif 3.1415 85827
pir 3.1415 82489
1000000
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 5364
pir 3.14159 1549
10000000
pi- 3.14159 2503 previous float
pi 3.14159 2741 machine float pi
pi+ 3.14159 2979 next float
pif 3.14159 6794
pir 3.14159 2503
100000000 Additional iterations do not improve the result.
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 6794
pir 3.14159 2503
1000000000
pi- 3.14159 2503
pi 3.14159 2741
pi+ 3.14159 2979
pif 3.14159 6794
pir 3.14159 2503