github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/gc/mpfloat.go (about) 1 // Copyright 2009 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 gc 6 7 import ( 8 "fmt" 9 "math" 10 "math/big" 11 ) 12 13 // implements float arithmetic 14 15 const ( 16 // Maximum size in bits for Mpints before signalling 17 // overflow and also mantissa precision for Mpflts. 18 Mpprec = 512 19 // Turn on for constant arithmetic debugging output. 20 Mpdebug = false 21 ) 22 23 // Mpflt represents a floating-point constant. 24 type Mpflt struct { 25 Val big.Float 26 } 27 28 // Mpcplx represents a complex constant. 29 type Mpcplx struct { 30 Real Mpflt 31 Imag Mpflt 32 } 33 34 func newMpflt() *Mpflt { 35 var a Mpflt 36 a.Val.SetPrec(Mpprec) 37 return &a 38 } 39 40 func newMpcmplx() *Mpcplx { 41 var a Mpcplx 42 a.Real = *newMpflt() 43 a.Imag = *newMpflt() 44 return &a 45 } 46 47 func (a *Mpflt) SetInt(b *Mpint) { 48 if b.checkOverflow(0) { 49 // sign doesn't really matter but copy anyway 50 a.Val.SetInf(b.Val.Sign() < 0) 51 return 52 } 53 a.Val.SetInt(&b.Val) 54 } 55 56 func (a *Mpflt) Set(b *Mpflt) { 57 a.Val.Set(&b.Val) 58 } 59 60 func (a *Mpflt) Add(b *Mpflt) { 61 if Mpdebug { 62 fmt.Printf("\n%v + %v", a, b) 63 } 64 65 a.Val.Add(&a.Val, &b.Val) 66 67 if Mpdebug { 68 fmt.Printf(" = %v\n\n", a) 69 } 70 } 71 72 func (a *Mpflt) AddFloat64(c float64) { 73 var b Mpflt 74 75 b.SetFloat64(c) 76 a.Add(&b) 77 } 78 79 func (a *Mpflt) Sub(b *Mpflt) { 80 if Mpdebug { 81 fmt.Printf("\n%v - %v", a, b) 82 } 83 84 a.Val.Sub(&a.Val, &b.Val) 85 86 if Mpdebug { 87 fmt.Printf(" = %v\n\n", a) 88 } 89 } 90 91 func (a *Mpflt) Mul(b *Mpflt) { 92 if Mpdebug { 93 fmt.Printf("%v\n * %v\n", a, b) 94 } 95 96 a.Val.Mul(&a.Val, &b.Val) 97 98 if Mpdebug { 99 fmt.Printf(" = %v\n\n", a) 100 } 101 } 102 103 func (a *Mpflt) MulFloat64(c float64) { 104 var b Mpflt 105 106 b.SetFloat64(c) 107 a.Mul(&b) 108 } 109 110 func (a *Mpflt) Quo(b *Mpflt) { 111 if Mpdebug { 112 fmt.Printf("%v\n / %v\n", a, b) 113 } 114 115 a.Val.Quo(&a.Val, &b.Val) 116 117 if Mpdebug { 118 fmt.Printf(" = %v\n\n", a) 119 } 120 } 121 122 func (a *Mpflt) Cmp(b *Mpflt) int { 123 return a.Val.Cmp(&b.Val) 124 } 125 126 func (a *Mpflt) CmpFloat64(c float64) int { 127 if c == 0 { 128 return a.Val.Sign() // common case shortcut 129 } 130 return a.Val.Cmp(big.NewFloat(c)) 131 } 132 133 func (a *Mpflt) Float64() float64 { 134 x, _ := a.Val.Float64() 135 136 // check for overflow 137 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 138 Fatalf("ovf in Mpflt Float64") 139 } 140 141 return x + 0 // avoid -0 (should not be needed, but be conservative) 142 } 143 144 func (a *Mpflt) Float32() float64 { 145 x32, _ := a.Val.Float32() 146 x := float64(x32) 147 148 // check for overflow 149 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 150 Fatalf("ovf in Mpflt Float32") 151 } 152 153 return x + 0 // avoid -0 (should not be needed, but be conservative) 154 } 155 156 func (a *Mpflt) SetFloat64(c float64) { 157 if Mpdebug { 158 fmt.Printf("\nconst %g", c) 159 } 160 161 // convert -0 to 0 162 if c == 0 { 163 c = 0 164 } 165 a.Val.SetFloat64(c) 166 167 if Mpdebug { 168 fmt.Printf(" = %v\n", a) 169 } 170 } 171 172 func (a *Mpflt) Neg() { 173 // avoid -0 174 if a.Val.Sign() != 0 { 175 a.Val.Neg(&a.Val) 176 } 177 } 178 179 func (a *Mpflt) SetString(as string) { 180 for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { 181 as = as[1:] 182 } 183 184 f, _, err := a.Val.Parse(as, 10) 185 if err != nil { 186 yyerror("malformed constant: %s (%v)", as, err) 187 a.Val.SetFloat64(0) 188 return 189 } 190 191 if f.IsInf() { 192 yyerror("constant too large: %s", as) 193 a.Val.SetFloat64(0) 194 return 195 } 196 197 // -0 becomes 0 198 if f.Sign() == 0 && f.Signbit() { 199 a.Val.SetFloat64(0) 200 } 201 } 202 203 func (f *Mpflt) String() string { 204 return f.Val.Text('b', 0) 205 } 206 207 func (fvp *Mpflt) GoString() string { 208 // determine sign 209 sign := "" 210 f := &fvp.Val 211 if f.Sign() < 0 { 212 sign = "-" 213 f = new(big.Float).Abs(f) 214 } 215 216 // Don't try to convert infinities (will not terminate). 217 if f.IsInf() { 218 return sign + "Inf" 219 } 220 221 // Use exact fmt formatting if in float64 range (common case): 222 // proceed if f doesn't underflow to 0 or overflow to inf. 223 if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) { 224 return fmt.Sprintf("%s%.6g", sign, x) 225 } 226 227 // Out of float64 range. Do approximate manual to decimal 228 // conversion to avoid precise but possibly slow Float 229 // formatting. 230 // f = mant * 2**exp 231 var mant big.Float 232 exp := f.MantExp(&mant) // 0.5 <= mant < 1.0 233 234 // approximate float64 mantissa m and decimal exponent d 235 // f ~ m * 10**d 236 m, _ := mant.Float64() // 0.5 <= m < 1.0 237 d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2) 238 239 // adjust m for truncated (integer) decimal exponent e 240 e := int64(d) 241 m *= math.Pow(10, d-float64(e)) 242 243 // ensure 1 <= m < 10 244 switch { 245 case m < 1-0.5e-6: 246 // The %.6g format below rounds m to 5 digits after the 247 // decimal point. Make sure that m*10 < 10 even after 248 // rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6. 249 m *= 10 250 e-- 251 case m >= 10: 252 m /= 10 253 e++ 254 } 255 256 return fmt.Sprintf("%s%.6ge%+d", sign, m, e) 257 } 258 259 // complex multiply v *= rv 260 // (a, b) * (c, d) = (a*c - b*d, b*c + a*d) 261 func (v *Mpcplx) Mul(rv *Mpcplx) { 262 var ac, ad, bc, bd Mpflt 263 264 ac.Set(&v.Real) 265 ac.Mul(&rv.Real) // ac 266 267 bd.Set(&v.Imag) 268 bd.Mul(&rv.Imag) // bd 269 270 bc.Set(&v.Imag) 271 bc.Mul(&rv.Real) // bc 272 273 ad.Set(&v.Real) 274 ad.Mul(&rv.Imag) // ad 275 276 v.Real.Set(&ac) 277 v.Real.Sub(&bd) // ac-bd 278 279 v.Imag.Set(&bc) 280 v.Imag.Add(&ad) // bc+ad 281 } 282 283 // complex divide v /= rv 284 // (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d) 285 func (v *Mpcplx) Div(rv *Mpcplx) bool { 286 if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 { 287 return false 288 } 289 290 var ac, ad, bc, bd, cc_plus_dd Mpflt 291 292 cc_plus_dd.Set(&rv.Real) 293 cc_plus_dd.Mul(&rv.Real) // cc 294 295 ac.Set(&rv.Imag) 296 ac.Mul(&rv.Imag) // dd 297 cc_plus_dd.Add(&ac) // cc+dd 298 299 // We already checked that c and d are not both zero, but we can't 300 // assume that c²+d² != 0 follows, because for tiny values of c 301 // and/or d c²+d² can underflow to zero. Check that c²+d² is 302 // nonzero, return if it's not. 303 if cc_plus_dd.CmpFloat64(0) == 0 { 304 return false 305 } 306 307 ac.Set(&v.Real) 308 ac.Mul(&rv.Real) // ac 309 310 bd.Set(&v.Imag) 311 bd.Mul(&rv.Imag) // bd 312 313 bc.Set(&v.Imag) 314 bc.Mul(&rv.Real) // bc 315 316 ad.Set(&v.Real) 317 ad.Mul(&rv.Imag) // ad 318 319 v.Real.Set(&ac) 320 v.Real.Add(&bd) // ac+bd 321 v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd) 322 323 v.Imag.Set(&bc) 324 v.Imag.Sub(&ad) // bc-ad 325 v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd) 326 327 return true 328 } 329 330 func (v *Mpcplx) String() string { 331 return fmt.Sprintf("(%s+%si)", v.Real.String(), v.Imag.String()) 332 } 333 334 func (v *Mpcplx) GoString() string { 335 var re string 336 sre := v.Real.CmpFloat64(0) 337 if sre != 0 { 338 re = v.Real.GoString() 339 } 340 341 var im string 342 sim := v.Imag.CmpFloat64(0) 343 if sim != 0 { 344 im = v.Imag.GoString() 345 } 346 347 switch { 348 case sre == 0 && sim == 0: 349 return "0" 350 case sre == 0: 351 return im + "i" 352 case sim == 0: 353 return re 354 case sim < 0: 355 return fmt.Sprintf("(%s%si)", re, im) 356 default: 357 return fmt.Sprintf("(%s+%si)", re, im) 358 } 359 }