golang中小数平方根的任意精度

时间:2015-05-19 04:12:28

标签: go precision

我正在寻找一种方法来计算一个任意精度的平方根(点之后的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,它会迭代地尝试计算答案吗?

2 个答案:

答案 0 :(得分:5)

这是我自己的平方根计算实现。在等待答案时,我决定尝试methods of computing square roots。它有很多方法,但最后我找到了一个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&#39;

的最后一位数字
getcontext().prec = 50
print str(Decimal(8537341).sqrt())
  

2921.8728582879851242173838229735693053765773170488

这个数字是关闭的,因为最后一位数字并不精确。

一如既往 Go Playground

P.S。如果有人会找到本地方式来做这件事,我很乐意接受我的接受和支持。

答案 1 :(得分:3)

添加精度

可能有一个解决方案,但由于我没有代码,这是一个通用的解决方案。

例如,如果您选择的语言没有提供解决方案来处理浮动的精确度(已发生在我身上):

如果您的语言在点后面提供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返回33.33