1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package big
import "math"
var (
half = NewFloat(0.5)
two = NewFloat(2.0)
three = NewFloat(3.0)
)
// Sqrt sets z to the rounded square root of x, and returns it.
//
// If z's precision is 0, it is changed to x's precision before the
// operation. Rounding is performed according to z's precision and
// rounding mode.
//
// The function panics if z < 0. The value of z is undefined in that
// case.
func (z *Float) Sqrt(x *Float) *Float {
if debugFloat {
x.validate()
}
if z.prec == 0 {
z.prec = x.prec
}
if x.Sign() == -1 {
// following IEEE754-2008 (section 7.2)
panic(ErrNaN{"square root of negative operand"})
}
// handle ±0 and +∞
if x.form != finite {
z.acc = Exact
z.form = x.form
z.neg = x.neg // IEEE754-2008 requires √±0 = ±0
return z
}
// MantExp sets the argument's precision to the receiver's, and
// when z.prec > x.prec this will lower z.prec. Restore it after
// the MantExp call.
prec := z.prec
b := x.MantExp(z)
z.prec = prec
// Compute √(z·2**b) as
// √( z)·2**(½b) if b is even
// √(2z)·2**(⌊½b⌋) if b > 0 is odd
// √(½z)·2**(⌈½b⌉) if b < 0 is odd
switch b % 2 {
case 0:
// nothing to do
case 1:
z.Mul(two, z)
case -1:
z.Mul(half, z)
}
// 0.25 <= z < 2.0
// Solving x² - z = 0 directly requires a Quo call, but it's
// faster for small precisions.
//
// Solving 1/x² - z = 0 avoids the Quo call and is much faster for
// high precisions.
//
// 128bit precision is an empirically chosen threshold.
if z.prec <= 128 {
z.sqrtDirect(z)
} else {
z.sqrtInverse(z)
}
// re-attach halved exponent
return z.SetMantExp(z, b/2)
}
// Compute √x (up to prec 128) by solving
// t² - x = 0
// for t, starting with a 53 bits precision guess from math.Sqrt and
// then using at most two iterations of Newton's method.
func (z *Float) sqrtDirect(x *Float) {
// let
// f(t) = t² - x
// then
// g(t) = f(t)/f'(t) = ½(t² - x)/t
// and the next guess is given by
// t2 = t - g(t) = ½(t² + x)/t
u := new(Float)
ng := func(t *Float) *Float {
u.prec = t.prec
u.Mul(t, t) // u = t²
u.Add(u, x) // = t² + x
u.Mul(half, u) // = ½(t² + x)
return t.Quo(u, t) // = ½(t² + x)/t
}
xf, _ := x.Float64()
sq := NewFloat(math.Sqrt(xf))
switch {
case z.prec > 128:
panic("sqrtDirect: only for z.prec <= 128")
case z.prec > 64:
sq.prec *= 2
sq = ng(sq)
fallthrough
default:
sq.prec *= 2
sq = ng(sq)
}
z.Set(sq)
}
// Compute √x (to z.prec precision) by solving
// 1/t² - x = 0
// for t (using Newton's method), and then inverting.
func (z *Float) sqrtInverse(x *Float) {
// let
// f(t) = 1/t² - x
// then
// g(t) = f(t)/f'(t) = -½t(1 - xt²)
// and the next guess is given by
// t2 = t - g(t) = ½t(3 - xt²)
u := new(Float)
ng := func(t *Float) *Float {
u.prec = t.prec
u.Mul(t, t) // u = t²
u.Mul(x, u) // = xt²
u.Sub(three, u) // = 3 - xt²
u.Mul(t, u) // = t(3 - xt²)
return t.Mul(half, u) // = ½t(3 - xt²)
}
xf, _ := x.Float64()
sqi := NewFloat(1 / math.Sqrt(xf))
for prec := z.prec + 32; sqi.prec < prec; {
sqi.prec *= 2
sqi = ng(sqi)
}
// sqi = 1/√x
// x/√x = √x
z.Mul(x, sqi)
}
|