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?
source to share
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.
source to share
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
.
source to share