Arbitrary precision for decimals square roots in golang

浪子不回头ぞ 提交于 2020-01-15 01:22:10

问题


I am looking for a way to calculate a square root with an arbitrary precision (something like 50 digits after the dot).

In python, it is easily accessible with Decimal:

from decimal import *
getcontext().prec = 50
Decimal(2).sqrt() # and here you go my 50 digits

After seeing the power of math/big I skimmed through the documentation but have not found anything similar.

So is my only option is to write some sort of numerical computing method which will iteratively try to compute the answer?


回答1:


This is my own implementation of square root calculation. While waiting for answers, I decided to give 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, which I really liked because the description of the algorithm is only a couple of lines (and I have not seen it before in comparison to Newton's method).

So here is my implementation (bigint is not really nice to work with in 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. thank you Nick Craig-Wood for making the code better with your amazing comment.

And using it, one can find that square(8537341, 50) is:

2921.8728582879851242173838229735693053765773170487

which is only by one last digit of from python's

getcontext().prec = 50
print str(Decimal(8537341).sqrt())

2921.8728582879851242173838229735693053765773170488

This one digit is off because the last digit is not really precise.

As always Go Playground.

P.S. if someone would find a native way to do this, I would gladly give my accept and upvote.




回答2:


Adding precision

There is probably a solution in go but as I don't code in go, here is a general solution.

For instance if your selected language doesn't provide a solution to handle the precision of floats (already happened to me):

If your language provides you N digits after the dot, you can, in the case of the square root, multiply the input, here 2, by 10^(2*number_of_extra_digits).

For instance if go would give you only 1.41 as an answer but you would want 1.4142, then you ask it the square root of 2*10^(2*2) = 2*10000 instead and you get 141.42 as an answer. Now I leave it up to you to rectify the placement of the dot.

Explanation: There is some math magic behind it.

If you were to want to add some precision to a simple division, you would just need to multiply the input by 10^number_of_extra_digits.

The trick is to multiply the input to get more precision as we can't multiply the output (the lost of precision already happened). It does work because most languages cut more decimals after the dot, than before it.

So we just need to change the output equation to the input equation (when possible):

For simple division: (a/b) * 10 = (a*10)/b

For square root: sqrt(a) * 10 = sqrt(a) * sqrt(100) = sqrt(a*100)

Reducing precision

Some similar tinkering can also help to reduce the precision if needed.

For instance if you were trying to calculate the progression of a download in percent, two digits after the dot.

Let's say we downloaded 1 file on 3, then 1/3 * 100 would give us 33.33333333.

If there is no way to control the precision of this float, then you could do cast_to_an_int(1/3 * 100 * 100) / 100 to return 33.33.



来源:https://stackoverflow.com/questions/30316639/arbitrary-precision-for-decimals-square-roots-in-golang

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!