golang中小数平方根的任意精度
Arbitrary precision for decimals square roots in golang
我正在寻找一种以任意精度(点后 50 位数字)计算平方根的方法。
在 python 中,可以通过 Decimal:
轻松访问
from decimal import *
getcontext().prec = 50
Decimal(2).sqrt() # and here you go my 50 digits
看到 math/big
的强大功能后,我浏览了 documentation 但没有发现任何类似的东西。
那么我唯一的选择是编写某种 numerical computing method 来迭代地尝试计算答案吗?
增加精度
在 go 中可能有一个解决方案,但由于我不会在 go 中编写代码,这里是一个通用的解决方案。
例如,如果您选择的语言没有提供处理浮点数精度的解决方案(我已经遇到过):
如果您的语言在点后为您提供 N 位数字,则在平方根的情况下,您可以将输入 2
乘以 10^(2*number_of_extra_digits)
。
例如,如果 go 只会给你 1.41
作为答案,但你想要 1.4142
,那么你问它 2*10^(2*2) = 2*10000
的平方根,你会得到 141.42
作为答案。现在我将由您来纠正点的位置。
解释:它背后有一些数学魔法。
如果您想为简单除法增加一些精度,只需将输入乘以 10^number_of_extra_digits
。
诀窍是乘以输入以获得更高的精度,因为我们不能乘以输出(精度丢失已经发生)。它确实有效,因为大多数语言在点之后比点之前削减了更多的小数。
所以我们只需要将输出方程更改为输入方程(如果可能):
简单除法:(a/b) * 10 = (a*10)/b
求平方根:sqrt(a) * 10 = sqrt(a) * sqrt(100) = sqrt(a*100)
降低精度
如果需要,一些类似的修补也可以帮助降低精度。
例如,如果您尝试以百分比(点后两位数)计算下载进度。
假设我们在 3 上下载了 1 个文件,那么 1/3 * 100
会给我们 33.33333333
。
如果没有办法控制这个浮点数的精度,那么你可以做cast_to_an_int(1/3 * 100 * 100) / 100
到return 33.33
.
这是我自己实现的平方根计算。在等待答案的时候,我决定给 methods of computing square roots a try. It has a whole bunch of methods but at the very end I found a link to a Square roots by subtraction pdf,我真的很喜欢,因为算法的描述只有几行(和牛顿法相比,我以前没见过它)。
所以这是我的实现(bigint 不太适合在 go 中使用):
func square(n int64, precision int64) string{
ans_int := strconv.Itoa(int(math.Sqrt(float64(n))))
limit := new(big.Int).Exp(big.NewInt(10), big.NewInt(precision + 1), nil)
a := big.NewInt(5 * n)
b := big.NewInt(5)
five := big.NewInt(5)
ten := big.NewInt(10)
hundred := big.NewInt(100)
for b.Cmp(limit) < 0{
if a.Cmp(b) < 0{
a.Mul(a, hundred)
tmp := new(big.Int).Div(b, ten)
tmp.Mul(tmp, hundred)
b.Add(tmp, five)
} else {
a.Sub(a, b)
b.Add(b, ten)
}
}
b.Div(b, hundred)
ans_dec := b.String()
return ans_dec[:len(ans_int)] + "." + ans_dec[len(ans_int):]
}
P.S. 感谢 Nick Craig-Wood 通过您的精彩评论使代码变得更好。
并利用它,可以发现square(8537341, 50)
是:
2921.8728582879851242173838229735693053765773170487
仅比 python 的
的最后一位
getcontext().prec = 50
print str(Decimal(8537341).sqrt())
2921.8728582879851242173838229735693053765773170488
这个数字是关闭的,因为最后一个数字不是很精确。
一如既往Go Playground.
P.S. 如果有人能找到一种本地方法来做到这一点,我很乐意给予我的接受和支持。
我正在寻找一种以任意精度(点后 50 位数字)计算平方根的方法。
在 python 中,可以通过 Decimal:
轻松访问from decimal import *
getcontext().prec = 50
Decimal(2).sqrt() # and here you go my 50 digits
看到 math/big
的强大功能后,我浏览了 documentation 但没有发现任何类似的东西。
那么我唯一的选择是编写某种 numerical computing method 来迭代地尝试计算答案吗?
增加精度
在 go 中可能有一个解决方案,但由于我不会在 go 中编写代码,这里是一个通用的解决方案。
例如,如果您选择的语言没有提供处理浮点数精度的解决方案(我已经遇到过):
如果您的语言在点后为您提供 N 位数字,则在平方根的情况下,您可以将输入 2
乘以 10^(2*number_of_extra_digits)
。
例如,如果 go 只会给你 1.41
作为答案,但你想要 1.4142
,那么你问它 2*10^(2*2) = 2*10000
的平方根,你会得到 141.42
作为答案。现在我将由您来纠正点的位置。
解释:它背后有一些数学魔法。
如果您想为简单除法增加一些精度,只需将输入乘以 10^number_of_extra_digits
。
诀窍是乘以输入以获得更高的精度,因为我们不能乘以输出(精度丢失已经发生)。它确实有效,因为大多数语言在点之后比点之前削减了更多的小数。
所以我们只需要将输出方程更改为输入方程(如果可能):
简单除法:(a/b) * 10 = (a*10)/b
求平方根:sqrt(a) * 10 = sqrt(a) * sqrt(100) = sqrt(a*100)
降低精度
如果需要,一些类似的修补也可以帮助降低精度。
例如,如果您尝试以百分比(点后两位数)计算下载进度。
假设我们在 3 上下载了 1 个文件,那么 1/3 * 100
会给我们 33.33333333
。
如果没有办法控制这个浮点数的精度,那么你可以做cast_to_an_int(1/3 * 100 * 100) / 100
到return 33.33
.
这是我自己实现的平方根计算。在等待答案的时候,我决定给 methods of computing square roots a try. It has a whole bunch of methods but at the very end I found a link to a Square roots by subtraction pdf,我真的很喜欢,因为算法的描述只有几行(和牛顿法相比,我以前没见过它)。
所以这是我的实现(bigint 不太适合在 go 中使用):
func square(n int64, precision int64) string{
ans_int := strconv.Itoa(int(math.Sqrt(float64(n))))
limit := new(big.Int).Exp(big.NewInt(10), big.NewInt(precision + 1), nil)
a := big.NewInt(5 * n)
b := big.NewInt(5)
five := big.NewInt(5)
ten := big.NewInt(10)
hundred := big.NewInt(100)
for b.Cmp(limit) < 0{
if a.Cmp(b) < 0{
a.Mul(a, hundred)
tmp := new(big.Int).Div(b, ten)
tmp.Mul(tmp, hundred)
b.Add(tmp, five)
} else {
a.Sub(a, b)
b.Add(b, ten)
}
}
b.Div(b, hundred)
ans_dec := b.String()
return ans_dec[:len(ans_int)] + "." + ans_dec[len(ans_int):]
}
P.S. 感谢 Nick Craig-Wood 通过您的精彩评论使代码变得更好。
并利用它,可以发现square(8537341, 50)
是:
2921.8728582879851242173838229735693053765773170487
仅比 python 的
的最后一位getcontext().prec = 50
print str(Decimal(8537341).sqrt())
2921.8728582879851242173838229735693053765773170488
这个数字是关闭的,因为最后一个数字不是很精确。
一如既往Go Playground.
P.S. 如果有人能找到一种本地方法来做到这一点,我很乐意给予我的接受和支持。