Arbitrary precision for decimal square roots in golang

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

In python, it is readily available with Decimal :

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

      

After looking at the power, math/big

I went through the documentation but couldn't find anything like it.

So my only option is to write some numerical computation method that iteratively tries to compute the answer?

+3


source to share


2 answers


This is my own implementation of calculating the square root. While waiting for answers, I decided to give methods for calculating square roots . It has a whole bunch of methods, but at the very end I found a link to Square roots by subtraction pdf, which I really liked because the description of the algorithm is just a couple of lines (and I have not seen this before compared to Newton's method).

So here's my implementation (bigint isn't very nice to work with 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):]
}

      

PS thanks Nick Craig-Wood for making the code better with your great comment.

And using it, you can find that square(8537341, 50)

:

2921.8728582879851242173838229735693053765773170487



which is on only one last digit of

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

      

2921.8728582879851242173838229735693053765773170488

This digit is off because the last digit is not very accurate.

As always . Go Playground

PS , if someone finds a native way to do this, I gladly give my consent and support.

+5


source


Adding precision

There may be a solution in go, but since I am not coding in go, here is a general solution.

For example, if the language of your choice does not provide a solution for handling the precision of floats (already happened to me):

If your language gives you N digits after the dot, you can multiply the input, here 2

, by 10^(2*number_of_extra_digits)

.

For example, if go only gives you 1.41

as an answer, but you want 1.4142

, then you ask it instead of the square root 2*10^(2*2) = 2*10000

and you get it 141.42

as an answer. Now I leave this for you to fix the dot placement.

Explanation: There is mathematical magic behind this.

If you need to add some precision to prime division, you just need to multiply the input by 10^number_of_extra_digits

.

The trick is to multiply the input to get more precision, since we cannot multiply the result (the loss of precision has already occurred). It works because most languages ​​truncate more decimal places after the dot than before.



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 the square root: sqrt(a) * 10 = sqrt(a) * sqrt(100) = sqrt(a*100)

Decrease in accuracy

Some of these interventions can also help reduce accuracy, if needed.

For example, if you were trying to calculate your download progression as a percentage, two digits after the period.

Let's say we downloaded 1 file by 3, then it 1/3 * 100

will provide us with 33.33333333

.

If there is no way to control the accuracy of this float, you can make a cast_to_an_int(1/3 * 100 * 100) / 100

return 33.33

.

+3


source







All Articles