我一直在尝试制作一个可以计算pi的第n位数字的小程序。
经过几次搜索后,我发现最常用的公式是BBP公式,这是第n个数字= 16 ^ -n [4/(8n +1)-2/(8n + 4)-1/(8n + 5)-1/(8n + 6)]。
输出以16为底。
我的代码如下:
function run(n) {
return Math.pow(16, -n) * (4 / (8 * n + 1) - 2 / (8 * n + 4) - 1 / (8 * n + 5) - 1 / (8 * n + 6));
}
function convertFromBaseToBase(str, fromBase, toBase) {
var num = parseInt(str, fromBase);
return num.toString(toBase);
}
for (var i = 0; i < 10; i++) {
var a = run(i);
console.log(convertFromBaseToBase(a, 16, 10));
}
到目前为止,我的输出如下:
1:3
2:0
3:0
4:0
5:1
6:7
7:3
8:1
9:7
10:3
显然,这些不是PI的前10位。
我的理解是,值(value)观过于频繁地四舍五入,并最终导致巨大的不确定性。
但是,我可能是错的,这就是为什么我在这里问我做错了什么,或者这是nodejs的错。因此,如果你们中的一个人对我的问题有答案,我会情有独钟!
谢谢!!
最佳答案
不幸的是,4/(8n + 1) - 2/(8n + 4) - 1/(8n + 5) - 1/(8n + 6)
不会直接返回pi的第N个十六进制数字。我不怪你,起初我做同样的假设。尽管所有术语的确加和为pi,但是每个单独的术语都不代表单个的十六进制数字。如here所示,必须对算法进行稍微的重写,才能正确地充当“数字插头”。这是新的run
实现的样子:
/**
Bailey-Borwein-Plouffe digit-extraction algorithm for pi
<https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula#BBP_digit-extraction_algorithm_for_.CF.80>
*/
function run(n) {
var partial = function(d, c) {
var sum = 0;
// Left sum
var k;
for (k = 0; k <= d - 1; k++) {
sum += (Math.pow(16, d - 1 - k) % (8 * k + c)) / (8 * k + c);
}
// Right sum. This converges fast...
var prev = undefined;
for(k = d; sum !== prev; k++) {
prev = sum;
sum += Math.pow(16, d - 1 - k) / (8 * k + c);
}
return sum;
};
/**
JavaScript's modulus operator gives the wrong
result for negative numbers. E.g. `-2.9 % 1`
returns -0.9, the correct result is 0.1.
*/
var mod1 = function(x) {
return x < 0 ? 1 - (-x % 1) : x % 1;
};
var s = 0;
s += 4 * partial(n, 1);
s += -2 * partial(n, 4);
s += -1 * partial(n, 5);
s += -1 * partial(n, 6);
s = mod1(s);
return Math.floor(s * 16);
}
// Pi in hex is 3.243f6a8885a308d313198a2e037073...
console.log(run(0) === 3); // 0th hexadecimal digit of pi is the leading 3
console.log(run(1) === 2);
console.log(run(2) === 4);
console.log(run(3) === 3);
console.log(run(4) === 15); // i.e. "F"
另外,您的
convertFromBaseToBase
函数比需要的复杂。您已经编写了它来接受特定基数的字符串,但是已经为它传递了一个数字(没有特定基数)。您真正需要的是:for (var i = 0; i < 10; i++) {
var a = run(i);
console.log(a.toString(16));
}
输出:
3
2
4
3
f
6
a
8
8
8
我已经测试了pi的前30个十六进制数字的代码,但是一旦
Math.pow(16, d - 1 - k)
超出Number.MAX_SAFE_INTEGER
,或者由于其他原因,它可能开始返回不正确的结果。那时,您可能需要实现Wikipedia文章中建议的模块化求幂技术。