| // 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" |
| "sync" |
| ) |
| |
| var threeOnce struct { |
| sync.Once |
| v *Float |
| } |
| |
| func three() *Float { |
| threeOnce.Do(func() { |
| threeOnce.v = NewFloat(3.0) |
| }) |
| return threeOnce.v |
| } |
| |
| // 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, but z's accuracy is not computed. Specifically, the |
| // result of z.Acc() is undefined. |
| // |
| // 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.exp++ |
| case -1: |
| z.exp-- |
| } |
| // 0.25 <= z < 2.0 |
| |
| // Solving 1/x² - z = 0 avoids Quo calls and is faster, especially |
| // for high precisions. |
| z.sqrtInverse(z) |
| |
| // re-attach halved exponent |
| return z.SetMantExp(z, b/2) |
| } |
| |
| // 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 := newFloat(z.prec) |
| v := newFloat(z.prec) |
| three := three() |
| ng := func(t *Float) *Float { |
| u.prec = t.prec |
| v.prec = t.prec |
| u.Mul(t, t) // u = t² |
| u.Mul(x, u) // = xt² |
| v.Sub(three, u) // v = 3 - xt² |
| u.Mul(t, v) // u = t(3 - xt²) |
| u.exp-- // = ½t(3 - xt²) |
| return t.Set(u) |
| } |
| |
| xf, _ := x.Float64() |
| sqi := newFloat(z.prec) |
| sqi.SetFloat64(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) |
| } |
| |
| // newFloat returns a new *Float with space for twice the given |
| // precision. |
| func newFloat(prec2 uint32) *Float { |
| z := new(Float) |
| // nat.make ensures the slice length is > 0 |
| z.mant = z.mant.make(int(prec2/_W) * 2) |
| return z |
| } |