首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用有限数学运算符查找多维数据集根

使用有限数学运算符查找多维数据集根
EN

Stack Overflow用户
提问于 2018-12-21 03:03:58
回答 6查看 699关注 0票数 0

我需要写一个函数来告诉我一个数字是否是一个完美的立方体。如果是,我希望按如下方式返回多维数据集根,否则为false:

代码语言:javascript
复制
cubeRoot(1)   // 1
cubeRoot(8)   // 2
cubeRoot(9)   // false
cubeRoot(27)  // 3
cubeRoot(28)  // false

它一定适用于很大的数字。表现是一项巨大的奖励。

但是,我使用的库意味着我只能使用以下数学函数/运算符:

代码语言:javascript
复制
abs, round, sqrt
/ * + -
===
> >= < <=
%
^

如果在JS中只使用上面的操作符提供答案,我可以自己将答案转换为(big.js)语法(我正在使用的库)。这个是可能的吗?

PS,我需要使用big.js,因为它保证了精度。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2018-12-21 16:50:23

这里是与Kamilłczewski代码相同的另一个版本,但是使用了łAPI,并依赖于它的实现细节。

代码语言:javascript
复制
function isZero(v) {
    let digits = v.c;
    return digits.length === 1 && digits[0] === 0;
}

function isInteger(v) {
    if (isZero(v))
        return true;
    return v.c.length <= v.e + 1;
}

function neg(v) {
    return new Big(0).minus(v);
}


function cubeRoot(v) {
    const ZERO = Big(0);
    const TEN = new Big(10);

    let c0 = v.cmp(ZERO);
    if (c0 === 0)
        return ZERO;
    if (c0 < 0) {
        let abs3 = cubeRoot(v.abs());
        if (abs3 instanceof Big)
            return neg(abs3);
        else
            return abs3;
    }

    if (!isInteger(v))
        return false;

    // use 10 because it should be fast given the way the value is stored inside Big
    let left = TEN.pow(Math.floor(v.e / 3));
    if (left.pow(3).eq(v))
        return left;

    let right = left.times(TEN);

    while (true) {
        let middle = left.plus(right).div(2);
        if (!isInteger(middle)) {
            middle = middle.round(0, 0); // round down
        }
        if (middle.eq(left))
            return false;
        let m3 = middle.pow(3);
        let cmp = m3.cmp(v);
        if (cmp === 0)
            return middle;
        if (cmp < 0)
            left = middle;
        else
            right = middle;
    }
}

这段代码的主要思想是使用二进制搜索,但是搜索开始时对leftright的估计要比Kamil的代码要好一些。特别是,它依赖于这样一个事实,即Big以标准化的指数表示法存储该值:作为十进制数字和指数的数组。所以我们可以很容易地找到这样的n,以至于10^n <= cubeRoot(value) < 10^(n+1)。这个技巧应该可以减少循环中的几次迭代。可能使用牛顿-拉夫森迭代而不是简单的二进制搜索可能会更快一些,但我不认为在实践中您会发现两者之间的区别。

票数 3
EN

Stack Overflow用户

发布于 2018-12-21 03:54:29

您可以使用JS内置BigInt。我假设输入是正整数。对于while循环,我提供了时间复杂度近似,其中n是输入的十进制数。这个版本的答案是受Salix alba回答wiki“立方体根”的启发:

  1. 二进制搜索 O(n log2(10)/3) <= O(1.11*n) (对于n=1000,我得到1110次迭代--测试这里,-对于l=0r=a O(10/3 n)) 函数cubicRoot(a) { let d=Math.floor((a.toString(2)..length 1)/3);//二进制数字nuber /3设r= 2n ** BigInt(d+1);//右边界近似设l= 2n ** BigInt(d);//左边界近似设x=BigInt(l);设o=BigInt(0);//旧历史值;(1){o= x;y=x*x* x;y(i%60?‘):’\n‘+x).join(’‘);//将长数拆分成多行字符串。
票数 3
EN

Stack Overflow用户

发布于 2018-12-22 16:45:44

所以让我们来看看二进制的一些立方体。

代码语言:javascript
复制
2^3 = 8 = 100b (3 binary digits)
4^3 = 64 = 100 000b  (6 binary digits)
8^3 = 512 = 100 000 000b (9 binary digits)
(2^n)^3 = 2^(3n) = (3n binary digits).

因此,对于粗略的第一猜测,计算二进制数,d说,然后除以3,让n = d/3告诉我们立方体根数是否在2^n2^(n+1)之间。计数数字可以链接到对数的原始第一近似。

如果您无法访问二进制数字,只需重复地除以8(或8的幂),直到得到零的结果。

现在我们可以用牛顿-拉夫森到家里去解决了。维基百科立方根帮助我们给出了迭代公式。如果a是我们想要找到的数字,并且x_0是我们第一次使用上面的猜测

代码语言:javascript
复制
x_{n+1} = ( a / x_n^2 + 2 x_n ) / 3.

这可以非常快地收敛。例如,在a=12345678901234567890中,我们发现a介于8^21和8^22之间,因此立方体根必须介于2^21和2^22之间。

运行迭代

代码语言:javascript
复制
x_1 = 2333795, x_1^3 = 12711245751310434875 
x_2 = 2311422, x_2^3 = 12349168818517523448
x_3 = 2311204, x_3^3 = 12345675040784217664
x_4 = 2311204, x_4^3 = 12345675040784217664

我们看到,经过三次迭代,它已经收敛。检查表明,a介于2311204^3和2311205^3之间。

该算法可以在使用big.js进行计算时运行。上面的计算是使用Java的BigInt类完成的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53878669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档