我有一个big.Int
变量,希望找到它的立方根。
这是在图书馆的某个地方实现的吗? Exp函数似乎只取整数,big.Rat
似乎完全没有Exp。
答案 0 :(得分:2)
可悲的是,math/big包中没有这样的功能。这意味着你必须自己推出一些东西。最容易理解和实施的是Newton's method。
您只需选择一些起始编号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}}
(check this link带有公式的图像,SO很容易插入数学公式)。
您从猜测开始,并在前一个x_n接近下一个x_n时结束。你有多接近决定。
P.S.1 你可以寻找更复杂的数值方法来找到根(你需要更少的迭代来收敛)
P.S.2 如果您需要,我在Go中写了method for calculating arbitrary precision square roots。
答案 1 :(得分:0)
我已经为big.Int
实现了立方根函数,都使用了简单的二进制搜索和牛顿的方法(如Salvador Dali的公式)。尽管我很确定还有改进的余地,但这是我得到的代码:
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。