编辑:要求是模糊的,而不是计算pi的第n位数,他们只是希望pi到第n位不超出浮点数限制,所以蛮力方式适用于要求。
我需要计算第n个数字的PI,我想尝试使用BBP formula但遇到困难。我输入的等式似乎没有正确地给我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;
}
答案 0 :(得分:5)
无论您使用什么公式,您都需要任意精度算术才能获得超过16位数。 (因为“double”只有16位精度)。
Chudnovsky公式是计算Pi的最快已知公式,每学期收敛14位数。但是,有效实施起来非常困难。
由于此公式的复杂性,使用计算Pi的数量少于几千位是没有意义的。所以不要使用它,除非你准备好用任意精度算法全力以赴。
使用GMP库的Chudnovsky公式的良好开源实现在这里:http://gmplib.org/pi-with-gmp.html
答案 1 :(得分:4)
当BBP公式主要用于计算π的任意十六进制数字时,您似乎正在尝试计算π的十进制数字。基本上,BBP公式可以用来计算π的 n th 十六进制数字而不计算前面的数字,十六进制数字0,1,..., n - 1。
David H. Bailey(Bailey-Borwein-Plouffe的Bailey)写了C and Fortran code来计算使用BBP的π的 n th 十六进制数字式。在具有IEEE 754双算术的机器上,从0开始计算精确到 n ≈1.18×10 7 ;即π=(3.243F6A8 ...) 16 所以当 n = 3时程序的输出以“F”开头:
position = 3 fraction = 0.963509103793105 hex digits = F6A8885A30
我喜欢稍微修改C版本,以便命令行参数可以覆盖 n (代码中名为id
):
--- 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[])
答案 2 :(得分:4)
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个有效小数dgits,你需要的不超过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);
element [k]%=(2 * k + 1);
元素[k-1] + = q * k; // k是计数器,所以不要忘记乘法。
3。)取元素[0]。它等于10 *第一个数字,因此您需要输出元素[0] / 10
并存储
元素[0]%= 10;
但是有一个线索:牛顿公式的最大可能数字(2 * n)的最大和是2.所以你可以从元素[1]获得多达19/10。当添加到元素[0](在步骤1中乘以10)时,您可以获得90 + 19 = 109。所以它有时会发生输出数字[10]。在这种情况下,您知道正确的数字是0,并且必须将1添加到先前输出的数字。
有两种方法可以解决这个问题:
1。)在计算下一个数字之前不输出最后一个数字。此外,存储连续9的数量并将它们输出为9或1,然后输出0,具体取决于非9位数。
2。)将输出的数字放入结果数组中,如果[10]发生,你可以轻松添加1。
在我的电脑上,我可以在10秒内计算(以Java格式)10,000个十进制数字。复杂度为O(n ^ 2)。
元素[k]的值永远不会超过12 * k,因此在快速机器上使用64位长类型,您可以计算超过10 ^ 15位数(非常强大的数字)。