繁体   English   中英

是否有用于获取大整数立方根的 Go 函数?

[英]Is there a Go function for obtaining the cube root of a big integer?

我有一个big.Int变量,并希望找到它的立方根。

这是在图书馆的某个地方实现的吗? Exp 函数似乎只接受一个整数,而big.Rat似乎完全没有 Exp。

可悲的是,数学/大包中没有这样的功能。 这意味着你必须自己推出一些东西。 最容易理解和实现的方法之一牛顿法

您只需要选择一些起始数字x_0并使用递归公式在此处输入图片说明


您必须按以下方式使用它:让您的整数为b 然后你的x^3 = b^3和你的f(x) = x^3 - b^3f'(x) = 3 * x^2

所以你需要迭代: x_{n+1}=x_n - \\frac{x_{n}^{3} + b^3}{3x_{n}^{2}}

(用公式的图像检查这个链接,所以插入数学公式很糟糕)。

您从猜测开始,并在前一个 x_n 接近下一个时结束。 距离有多近由您决定。

PS1你可以寻找更复杂的数值方法来找到根(你需要更少的迭代来收敛)

PS2如果你需要,我写了一个在 Go 中计算任意精度平方根方法

我已经为big.Int实现了一个立方根函数,根据萨尔瓦多·达利的公式,使用简单的二分搜索和牛顿方法。 虽然我很确定还有改进的余地,但这是我得到的代码:

var (
    n0  = big.NewInt(0)
    n1  = big.NewInt(1)
    n2  = big.NewInt(2)
    n3  = big.NewInt(3)
    n10 = big.NewInt(10)
)

func cbrtBinary(i *big.Int) (cbrt *big.Int, rem *big.Int) {
    var (
        guess = new(big.Int).Div(i, n2)
        dx    = new(big.Int)
        absDx = new(big.Int)
        minDx = new(big.Int).Abs(i)
        step  = new(big.Int).Abs(new(big.Int).Div(guess, n2))
        cube  = new(big.Int)
    )
    for {
        cube.Exp(guess, n3, nil)
        dx.Sub(i, cube)
        cmp := dx.Cmp(n0)
        if cmp == 0 {
            return guess, n0
        }

        absDx.Abs(dx)
        switch absDx.Cmp(minDx) {
        case -1:
            minDx.Set(absDx)
        case 0:
            return guess, dx
        }

        switch cmp {
        case -1:
            guess.Sub(guess, step)
        case +1:
            guess.Add(guess, step)
        }

        step.Div(step, n2)
        if step.Cmp(n0) == 0 {
            step.Set(n1)
        }
    }
}

func cbrtNewton(i *big.Int) (cbrt *big.Int, rem *big.Int) {
    var (
        guess   = new(big.Int).Div(i, n2)
        guessSq = new(big.Int)
        dx      = new(big.Int)
        absDx   = new(big.Int)
        minDx   = new(big.Int).Abs(i)
        cube    = new(big.Int)
        fx      = new(big.Int)
        fxp     = new(big.Int)
        step    = new(big.Int)
    )
    for {
        cube.Exp(guess, n3, nil)
        dx.Sub(i, cube)
        cmp := dx.Cmp(n0)
        if cmp == 0 {
            return guess, n0
        }

        fx.Sub(cube, i)
        guessSq.Exp(guess, n2, nil)
        fxp.Mul(n3, guessSq)
        step.Div(fx, fxp)
        if step.Cmp(n0) == 0 {
            step.Set(n1)
        }

        absDx.Abs(dx)
        switch absDx.Cmp(minDx) {
        case -1:
            minDx.Set(absDx)
        case 0:
            return guess, dx
        }

        guess.Sub(guess, step)
    }
}

令人惊讶的是,简单的二进制算法也是最快的:

BenchmarkCbrt/binary/10e6-4       100000         19195 ns/op
BenchmarkCbrt/binary/10e12-4       30000         43634 ns/op
BenchmarkCbrt/binary/10e18-4       20000         73334 ns/op
BenchmarkCbrt/newton/10e6-4        30000         47027 ns/op
BenchmarkCbrt/newton/10e12-4       10000        123612 ns/op
BenchmarkCbrt/newton/10e18-4       10000        214884 ns/op

这是完整的代码,包括测试和基准测试: https : //play.golang.org/p/uoEmxRK5jgs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM