Bailey–Borwein–Plouffe formula implementation in C++?

一世执手 提交于 2019-12-04 05:14:23

Regardless of what formula you use, you will need arbitrary precision arithmetic to get more than 16 digits. (Since "double" only has 16 digits of precision).

The Chudnovsky Formula is the fastest known formula for computing Pi and converges at 14 digits per term. However, it is extremely difficult to implement efficiently.

Due to the complexity of this formula, there's no point in using to compute Pi to less than a few thousand digits. So don't use it unless you're ready to go all-out with arbitrary precision arithmetic.

A good open-sourced implementation of the Chudnovsky Formula using the GMP library is here: http://gmplib.org/pi-with-gmp.html

It looks like you are trying to calculate the decimal digits of π when the BBP formula is mainly used to calculate arbitrary hexadecimal digits of π. Basically, the BBP formula can be used to calculate the nth hexadecimal digit of π without computing the previous digits, hex digits 0, 1, ..., n - 1.

David H. Bailey (the Bailey of Bailey–Borwein–Plouffe) has written C and Fortran code to calculate the nth hexadecimal digit of π using the BBP formula. On a machine with IEEE 754 double arithmetic, it is accurate up to n ≈ 1.18 × 107 counting from 0; i.e. π = (3.243F6A8...)16 so the output of the program when n = 3 begins with “F”:

 position = 3
 fraction = 0.963509103793105
 hex digits =  F6A8885A30

I like to modify the C version slightly so that n (named id in the code) can be overridden by a command line argument:

--- piqpr8.c.orig   2011-10-08 14:54:46.840423000 -0400
+++ piqpr8.c    2011-10-08 15:04:41.524437000 -0400
@@ -14,14 +14,18 @@
 /*  David H. Bailey     2006-09-08 */

 #include <stdio.h>
+#include <stdlib.h>
 #include <math.h>

-main()
+int main(int argc, char *argv[])
 {
   double pid, s1, s2, s3, s4;
   double series (int m, int n);
   void ihex (double x, int m, char c[]);
   int id = 1000000;
+  if (argc == 2) {
+    id = atoi(argv[1]);
+  }
 #define NHX 16
   char chx[NHX];

@@ -36,6 +40,8 @@
   ihex (pid, NHX, chx);
   printf (" position = %i\n fraction = %.15f \n hex digits =  %10.10s\n",
   id, pid, chx);
+
+  return EXIT_SUCCESS;
 }

 void ihex (double x, int nhx, char chx[])
Tomek

The BBP formula is not suitable for easy finding of n-th decimal digit as it easily returns hex and only hex digits. So to recalculate into decimals you will need to collect all hex digits.

It is much better to use Newton formula:

Pi/2 = 1 + 1/3 + 1*2/3*5 + 1*2*3/3*5*7 + .... n!/(2n+1)!! + ....

It collapses to Horner's scheme:

Pi/2 = 1 + 1/3*(1 + 2/5*(1 + 3/7*(1 + ...... n/(2n+1)*(1) ..... )))

So you have Pi written as a positional series where on each fractional position you have different base used (n/(2n+1)), and all digits are equal to 2. It obviously converges, as that base is less than 1/2, so to calculate Pi up to n significant decimal dgits you need no more than log_2(10)*n terms (N = 10*n/3+1 is perfect stuff).

You start with the array of N integer elements, all equals 2, and repeatedly, n times, do the following:

1.) Multiply all elements by 10.

2.) Recalculate each element[k] (from N down to 1) to have a "digit" less then denominator (2*k+1),
but at the same time you need to move a qoutient to the left position, so:
q = element[k] / (2*k+1);
element[k] %= (2*k+1);
element[k-1] += q * k; //k is the counter, so don't forgrt to multiply.

3.) take element[0]. It equals 10 * first digit, so you need to output element[0] / 10 and store
element[0] %= 10;

BUT there is a clue: the maximal sum for maximal possible digits (2*n) of Newton formula is 2. So you can obtain as much as 19/10 from element[1]. When adding to element[0] (multiplied by 10 in step 1.) you can obtain 90+19=109. So it sometimes happens outputted digit will be [10]. In such a case you know, that the correct digit is 0, and the 1 must be added to the previously outputted digit.

There are two ways of solving this issue:

1.) Not to output the last digit until the next one is calculated. Moreover, store the number of consecutive nines and output them as nines or as 1 followed by zeros depending on first non 9 digit.

2.) Put outputted digits into result array, so you can easily add 1 if [10] occurs.

On my PC I can calculate (in Java) 10,000 decimal digits in 10 s. The complexity is O(n^2).

The values of element[k] never exceeds 12*k, so using 64-bit long type on fast machine you can calculate more than 10^15 digits (very robust approx.).

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!