github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/math/big/sqrt.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package big 6 7 import ( 8 "math" 9 "sync" 10 ) 11 12 var threeOnce struct { 13 sync.Once 14 v *Float 15 } 16 17 func three() *Float { 18 threeOnce.Do(func() { 19 threeOnce.v = NewFloat(3.0) 20 }) 21 return threeOnce.v 22 } 23 24 // Sqrt sets z to the rounded square root of x, and returns it. 25 // 26 // If z's precision is 0, it is changed to x's precision before the 27 // operation. Rounding is performed according to z's precision and 28 // rounding mode, but z's accuracy is not computed. Specifically, the 29 // result of z.Acc() is undefined. 30 // 31 // The function panics if z < 0. The value of z is undefined in that 32 // case. 33 func (z *Float) Sqrt(x *Float) *Float { 34 if debugFloat { 35 x.validate() 36 } 37 38 if z.prec == 0 { 39 z.prec = x.prec 40 } 41 42 if x.Sign() == -1 { 43 // following IEEE754-2008 (section 7.2) 44 panic(ErrNaN{"square root of negative operand"}) 45 } 46 47 // handle ±0 and +∞ 48 if x.form != finite { 49 z.acc = Exact 50 z.form = x.form 51 z.neg = x.neg // IEEE754-2008 requires √±0 = ±0 52 return z 53 } 54 55 // MantExp sets the argument's precision to the receiver's, and 56 // when z.prec > x.prec this will lower z.prec. Restore it after 57 // the MantExp call. 58 prec := z.prec 59 b := x.MantExp(z) 60 z.prec = prec 61 62 // Compute √(z·2**b) as 63 // √( z)·2**(½b) if b is even 64 // √(2z)·2**(⌊½b⌋) if b > 0 is odd 65 // √(½z)·2**(⌈½b⌉) if b < 0 is odd 66 switch b % 2 { 67 case 0: 68 // nothing to do 69 case 1: 70 z.exp++ 71 case -1: 72 z.exp-- 73 } 74 // 0.25 <= z < 2.0 75 76 // Solving 1/x² - z = 0 avoids Quo calls and is faster, especially 77 // for high precisions. 78 z.sqrtInverse(z) 79 80 // re-attach halved exponent 81 return z.SetMantExp(z, b/2) 82 } 83 84 // Compute √x (to z.prec precision) by solving 85 // 86 // 1/t² - x = 0 87 // 88 // for t (using Newton's method), and then inverting. 89 func (z *Float) sqrtInverse(x *Float) { 90 // let 91 // f(t) = 1/t² - x 92 // then 93 // g(t) = f(t)/f'(t) = -½t(1 - xt²) 94 // and the next guess is given by 95 // t2 = t - g(t) = ½t(3 - xt²) 96 u := newFloat(z.prec) 97 v := newFloat(z.prec) 98 three := three() 99 ng := func(t *Float) *Float { 100 u.prec = t.prec 101 v.prec = t.prec 102 u.Mul(t, t) // u = t² 103 u.Mul(x, u) // = xt² 104 v.Sub(three, u) // v = 3 - xt² 105 u.Mul(t, v) // u = t(3 - xt²) 106 u.exp-- // = ½t(3 - xt²) 107 return t.Set(u) 108 } 109 110 xf, _ := x.Float64() 111 sqi := newFloat(z.prec) 112 sqi.SetFloat64(1 / math.Sqrt(xf)) 113 for prec := z.prec + 32; sqi.prec < prec; { 114 sqi.prec *= 2 115 sqi = ng(sqi) 116 } 117 // sqi = 1/√x 118 119 // x/√x = √x 120 z.Mul(x, sqi) 121 } 122 123 // newFloat returns a new *Float with space for twice the given 124 // precision. 125 func newFloat(prec2 uint32) *Float { 126 z := new(Float) 127 // nat.make ensures the slice length is > 0 128 z.mant = z.mant.make(int(prec2/_W) * 2) 129 return z 130 }