有没有一个用于获取大整数立方根的Go函数?

huangapple go评论101阅读模式
英文:

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

问题

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

这个库中是否已经实现了这个功能?Exp函数似乎只接受整数作为参数,而big.Rat似乎完全没有Exp函数。

英文:

I have a big.Int variable, and wish to find the cube root of it.

Is this implemented somewhere in the library? The Exp function seems to only take an integer, and big.Rat seems to be lacking Exp entirely.

答案1

得分: 2

很遗憾,在math/big包中没有这样的函数。这意味着你需要自己实现一些东西。其中一个最容易理解和实现的方法是牛顿法

你只需要选择一个起始数x_0,然后使用递归公式有没有一个用于获取大整数立方根的Go函数?


你需要按照以下方式使用它:假设你的整数是b。那么你的x^3 = b^3f(x) = x^3 - b^3f'(x) = 3 * x^2

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

查看此链接以获取公式的图像,SO在插入数学公式方面不太好)。

你从一个猜测开始,当前一个x_n接近下一个x_n时结束。接近的程度由你决定。

附注1:你可以寻找更复杂的数值方法来找到根(收敛所需的迭代次数更少)。

附注2:如果需要,我在Go语言中编写了一个计算任意精度平方根的方法

英文:

Sadly but there is no such function in math/big package. This means that you have to roll out something on your own. One of the easiest to understand and implement is the Newton's method.

All you need is to select some starting number x_0 and use the recursive formula 有没有一个用于获取大整数立方根的Go函数?


You have to use it in the following way: Let your integer is b. Then your x^3 = b^3 and your f(x) = x^3 - b^3 and f'(x) = 3 * x^2.

So you need to iterate:
x_{n+1}=x_n - \frac{x_{n}^{3} + b^3}{3x_{n}^{2}}

(check this link with the image of the formula, SO sucks in inserting math formulas).

You start from a guess and ends when previous x_n is close to the next one. How close is for you to decide.

P.S.1 you can look for more complicated numerical methods to find roots (you will need less iterations to converge)

P.S.2 if you need, I wrote a method for calculating arbitrary precision square roots in Go.

答案2

得分: 2

我已经为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。

英文:

I've implemented a cube root function for big.Int, both using a simple binary search and Newton's method as per Salvador Dali's formula. Although I am pretty sure there is room for improvement, here is the code that I've got:

<!-- language: lang-golang -->

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)
}
}

Surprisingly enough, the simple binary algorithm is also the fastest:

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

Here is the full code, including tests and benchmarks: https://play.golang.org/p/uoEmxRK5jgs.

huangapple
  • 本文由 发表于 2015年7月6日 13:24:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/31238262.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定