不能让BBP公式在nodejs中工作

时间:2016-06-02 18:32:38

标签: javascript node.js math pi

我一直试图制作一个可以计算pi的第n位的小程序。

经过几次搜索,我发现最常见的公式是BBP公式,第n位= 16 ^ -n [4 /(8n + 1)-2 /(8n + 4) -1 /(8n + 5)-1 /(8n + 6)]。

输出位于16位。

我的代码如下:

1:3
2:0
3:0
4:0
5:1
6:7
7:3
8:1
9:7
10:3

到目前为止,我的输出如下:

{{1}}

显然,这些不是PI的10个第一位数。 我的理解是,价值观过于频繁,导致最终结果造成巨大的空洞现象。

然而,我可能是错的,这就是为什么我在这里问我是否做错了什么或者它是否是错误的。如果你们其中一个人能解决我的问题,我会很乐意! 谢谢!

1 个答案:

答案 0 :(得分:4)

不幸的是,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,或者由于其他原因可能更早,它可能会开始返回不准确的结果。此时,您可能需要实现维基百科文章中建议的模幂运算技术。