[英]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^3
和f'(x) = 3 * x^2
。
所以你需要迭代: x_{n+1}=x_n - \\frac{x_{n}^{3} + b^3}{3x_{n}^{2}}
(用公式的图像检查这个链接,所以插入数学公式很糟糕)。
您从猜测开始,并在前一个 x_n 接近下一个时结束。 距离有多近由您决定。
PS1你可以寻找更复杂的数值方法来找到根(你需要更少的迭代来收敛)
我已经为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.