Bailey–Borwein–Plouffe 公式在 C++ 中的实现?
编辑:要求很模糊,他们不计算 pi 的第 n 位数字,而是希望将 pi 计算到第 n 位数字而不超出浮点数限制,因此暴力方式可以满足要求。
我需要计算 PI 第 n 位数字,我想尝试使用 BBP 公式 但遇到困难。我输入的方程似乎没有正确给出 PI。
(1 / pow(16,n))((4 / (8 * n + 1)) - (2 / (8 * n + 4)) - (1 / (8 * n + 5)) - (1 / (8 * n + 6)))
我成功地用蛮力方法找到了 PI,但这只是那么准确,而且找到第 n 个数字很困难。
(4 - (4/3) + (4/5) - (4/7)...)
我想知道是否有人对如何做到这一点有更好的想法,或者可以帮助我解决我搞砸的 BBP 方程?
谢谢你,
LF4
功能正常,但在进行几次迭代之前不是很准确,然后您必须忽略最后几次。
#include <iostream>
using namespace std;
int main()
{
int loop_num = 0;
cout << "How many digits of pi do you want?: ";
cin >> loop_num;
double my_pi = 4.0;
bool add_check = false;
int den = 3;
for (int i = 0; i < loop_num; i++)
{
if (add_check)
{
my_pi += (4.0/den);
add_check = false;
den += 2;
}
else
{
my_pi -= (4.0/den);
add_check = true;
den += 2;
}
}
cout << "Calculated PI is: " << my_pi << endl;
system("pause");
return 0;
}
我希望能有一个更好的程序。
#include <iostream>
#include <cmath>
using namespace std;
const double PI_BASE = 16.0;
int main()
{
int loop_num = 0;
cout << "How many digits of pi do you want?: ";
cin >> loop_num;
double my_pi = 0.0;
for (int i = 0; i <= loop_num; i++)
{
my_pi += ( 1.0 / pow(PI_BASE,i) )( (4.0 / (8.0 * i + 1.0)) -
(2.0 / (8.0 * i + 4.0)) -
(1.0 / (8.0 * i + 5.0)) -
(1.0 / (8.0 * i + 6.0)) );
}
cout << "Calculated PI is: " << my_pi << endl;
system("pause");
return 0;
}
EDIT: The requirement was vague and instead of calculating the n-th digit of pi they just wanted pi to the n-th digit not going beyond floats limitation so the brute force way worked for the requirements.
I need to calculate PI the the n-th digit and I wanted to try using the BBP formula but am having difficulties. The equation I typed up doesn't seem to be giving me PI correctly.
(1 / pow(16,n))((4 / (8 * n + 1)) - (2 / (8 * n + 4)) - (1 / (8 * n + 5)) - (1 / (8 * n + 6)))
I was successful with the brute force way of finding PI but that is only so accurate and finding the nth number is difficult.
(4 - (4/3) + (4/5) - (4/7)...)
I wanted to find out if anyone had a better idea of how to do this or maybe help with my BBP equation on what I messed up?
Thank you,
LF4
Functional but not very accurate until a few iterations in and then you have to disreguard the last few.
#include <iostream>
using namespace std;
int main()
{
int loop_num = 0;
cout << "How many digits of pi do you want?: ";
cin >> loop_num;
double my_pi = 4.0;
bool add_check = false;
int den = 3;
for (int i = 0; i < loop_num; i++)
{
if (add_check)
{
my_pi += (4.0/den);
add_check = false;
den += 2;
}
else
{
my_pi -= (4.0/den);
add_check = true;
den += 2;
}
}
cout << "Calculated PI is: " << my_pi << endl;
system("pause");
return 0;
}
What I'm hoping would be a better program.
#include <iostream>
#include <cmath>
using namespace std;
const double PI_BASE = 16.0;
int main()
{
int loop_num = 0;
cout << "How many digits of pi do you want?: ";
cin >> loop_num;
double my_pi = 0.0;
for (int i = 0; i <= loop_num; i++)
{
my_pi += ( 1.0 / pow(PI_BASE,i) )( (4.0 / (8.0 * i + 1.0)) -
(2.0 / (8.0 * i + 4.0)) -
(1.0 / (8.0 * i + 5.0)) -
(1.0 / (8.0 * i + 6.0)) );
}
cout << "Calculated PI is: " << my_pi << endl;
system("pause");
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无论使用什么公式,都需要任意精度算术才能获得超过 16 位的数字。 (因为“double”只有 16 位精度)。
Chudnovsky 公式是计算 Pi 最快的已知公式,每项收敛于 14 位数字。然而,有效实施却极其困难。
由于该公式的复杂性,将 Pi 计算为小于几千位是没有意义的。因此,除非您准备好全力以赴进行任意精度算术,否则不要使用它。
使用 GMP 库对 Chudnovsky Formula 进行良好的开源实现如下:http://gmplib .org/pi-with-gmp.html
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
当 BBP 公式主要用于计算 π 的任意十六进制数字时,看起来您正在尝试计算 π 的十进制数字。基本上,BBP 公式可以用来计算 π 的第 n 个十六进制数字,而无需计算前面的数字,十六进制数字 0, 1, ..., n - 1.
David H. Bailey(Bailey–Borwein–Plouffe 的贝利)撰写了 C 和 Fortran 代码,使用 BBP 公式计算 π 的n第位十六进制数字。在采用 IEEE 754 双精度算术的机器上,从 0 开始计数,精确度可达 n ≈ 1.18 × 107;即 π = (3.243F6A8...)16 所以当 n = 3 时程序的输出以“F”开头:
我喜欢稍微修改一下 C 版本,所以n(在代码中名为
id
)可以被命令行参数覆盖: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”:
I like to modify the C version slightly so that n (named
id
in the code) can be overridden by a command line argument:BBP 公式不适合轻松查找第 n 位十进制数字,因为它很容易返回十六进制且仅返回十六进制数字。因此,要重新计算为小数,您需要收集所有十六进制数字。
最好使用牛顿公式:
Pi/2 = 1 + 1/3 + 1*2/3*5 + 1*2*3/3*5*7 + .... n!/(2n+1 )!! + ....
它崩溃为霍纳的方案:
Pi/2 = 1 + 1/3*(1 + 2/5*(1 + 3/7*(1 + ...... n/(2n+1 )*(1) ..... )))
因此,您将 Pi 写成位置系列,其中在每个小数位置上使用不同的基数 (n/(2n+1)),并且所有数字都等于 2。它显然收敛了,因为该基数小于1/2,因此要计算 Pi 最多 n 个有效十进制数字,您只需要 log_2(10)*n 项(N = 10*n/3+1 是完美的东西)。
从 N 个整数元素的数组开始,全部等于 2,然后重复执行 n 次,执行以下操作:
1.) 将所有元素乘以 10。
2.) 重新计算每个元素[k](从 N 到 1)以有一个“数字”小于分母 (2*k+1),
但同时您需要将 qoutient 移至左侧位置,因此:
q = 元素[k] / (2*k+1);
元素[k] %= (2*k+1);
元素[k-1] += q * k; //k 是计数器,所以不要忘记相乘。
3.) 取元素[0]。它等于 10 * 第一个数字,因此您需要输出 element[0] / 10
并存储
element[0] %= 10;
但有一个线索:牛顿公式的最大可能位数 (2*n) 的最大和是 2。因此,您可以从 element[1] 获得多达 19/10。当添加到 element[0](在步骤 1 中乘以 10)时,您可以得到 90+19=109。所以有时输出的数字会是[10]。在这种情况下,您知道正确的数字是 0,并且必须将 1 添加到先前输出的数字上。
有两种方法可以解决这个问题:
1.) 在计算下一位之前不输出最后一位数字。此外,存储连续 9 的数量,并根据第一个非 9 数字将它们输出为 9 或 1 后跟 0。
2.) 将输出的数字放入结果数组中,这样如果出现[10]就可以轻松加1。
在我的 PC 上,我可以在 10 秒内计算(用 Java)10,000 个十进制数字。复杂度为O(n^2)。
element[k] 的值永远不会超过 12*k,因此在快速机器上使用 64 位长类型,您可以计算超过 10^15 位(大约非常稳健)。
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.).