github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/gc/mparith3.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 "cmd/internal/gc/big" 9 "cmd/internal/obj" 10 "fmt" 11 "math" 12 ) 13 14 /// implements float arihmetic 15 16 func newMpflt() *Mpflt { 17 var a Mpflt 18 a.Val.SetPrec(Mpprec) 19 return &a 20 } 21 22 func Mpmovefixflt(a *Mpflt, b *Mpint) { 23 if b.Ovf { 24 // sign doesn't really matter but copy anyway 25 a.Val.SetInf(b.Val.Sign() < 0) 26 return 27 } 28 a.Val.SetInt(&b.Val) 29 } 30 31 func mpmovefltflt(a *Mpflt, b *Mpflt) { 32 a.Val.Set(&b.Val) 33 } 34 35 func mpaddfltflt(a *Mpflt, b *Mpflt) { 36 if Mpdebug { 37 fmt.Printf("\n%v + %v", Fconv(a, 0), Fconv(b, 0)) 38 } 39 40 a.Val.Add(&a.Val, &b.Val) 41 42 if Mpdebug { 43 fmt.Printf(" = %v\n\n", Fconv(a, 0)) 44 } 45 } 46 47 func mpaddcflt(a *Mpflt, c float64) { 48 var b Mpflt 49 50 Mpmovecflt(&b, c) 51 mpaddfltflt(a, &b) 52 } 53 54 func mpsubfltflt(a *Mpflt, b *Mpflt) { 55 if Mpdebug { 56 fmt.Printf("\n%v - %v", Fconv(a, 0), Fconv(b, 0)) 57 } 58 59 a.Val.Sub(&a.Val, &b.Val) 60 61 if Mpdebug { 62 fmt.Printf(" = %v\n\n", Fconv(a, 0)) 63 } 64 } 65 66 func mpmulfltflt(a *Mpflt, b *Mpflt) { 67 if Mpdebug { 68 fmt.Printf("%v\n * %v\n", Fconv(a, 0), Fconv(b, 0)) 69 } 70 71 a.Val.Mul(&a.Val, &b.Val) 72 73 if Mpdebug { 74 fmt.Printf(" = %v\n\n", Fconv(a, 0)) 75 } 76 } 77 78 func mpmulcflt(a *Mpflt, c float64) { 79 var b Mpflt 80 81 Mpmovecflt(&b, c) 82 mpmulfltflt(a, &b) 83 } 84 85 func mpdivfltflt(a *Mpflt, b *Mpflt) { 86 if Mpdebug { 87 fmt.Printf("%v\n / %v\n", Fconv(a, 0), Fconv(b, 0)) 88 } 89 90 a.Val.Quo(&a.Val, &b.Val) 91 92 if Mpdebug { 93 fmt.Printf(" = %v\n\n", Fconv(a, 0)) 94 } 95 } 96 97 func mpcmpfltflt(a *Mpflt, b *Mpflt) int { 98 return a.Val.Cmp(&b.Val) 99 } 100 101 func mpcmpfltc(b *Mpflt, c float64) int { 102 var a Mpflt 103 104 Mpmovecflt(&a, c) 105 return mpcmpfltflt(b, &a) 106 } 107 108 func mpgetfltN(a *Mpflt, prec int, bias int) float64 { 109 var x float64 110 switch prec { 111 case 53: 112 x, _ = a.Val.Float64() 113 case 24: 114 // We should be using a.Val.Float32() here but that seems incorrect 115 // for certain denormal values (all.bash fails). The current code 116 // appears to work for all existing test cases, though there ought 117 // to be issues with denormal numbers that are incorrectly rounded. 118 // TODO(gri) replace with a.Val.Float32() once correctly working 119 // See also: https://github.com/golang/go/issues/10321 120 var t Mpflt 121 t.Val.SetPrec(24).Set(&a.Val) 122 x, _ = t.Val.Float64() 123 default: 124 panic("unreachable") 125 } 126 127 // check for overflow 128 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 129 Yyerror("mpgetflt ovf") 130 } 131 132 return x 133 } 134 135 func mpgetflt(a *Mpflt) float64 { 136 return mpgetfltN(a, 53, -1023) 137 } 138 139 func mpgetflt32(a *Mpflt) float64 { 140 return mpgetfltN(a, 24, -127) 141 } 142 143 func Mpmovecflt(a *Mpflt, c float64) { 144 if Mpdebug { 145 fmt.Printf("\nconst %g", c) 146 } 147 148 a.Val.SetFloat64(c) 149 150 if Mpdebug { 151 fmt.Printf(" = %v\n", Fconv(a, 0)) 152 } 153 } 154 155 func mpnegflt(a *Mpflt) { 156 a.Val.Neg(&a.Val) 157 } 158 159 // 160 // floating point input 161 // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] 162 // 163 func mpatoflt(a *Mpflt, as string) { 164 for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { 165 as = as[1:] 166 } 167 168 f, ok := a.Val.SetString(as) 169 if !ok { 170 // At the moment we lose precise error cause; 171 // the old code additionally distinguished between: 172 // - malformed hex constant 173 // - decimal point in hex constant 174 // - constant exponent out of range 175 // - decimal point and binary point in constant 176 // TODO(gri) use different conversion function or check separately 177 Yyerror("malformed constant: %s", as) 178 a.Val.SetUint64(0) 179 } 180 181 if f.IsInf() { 182 Yyerror("constant too large: %s", as) 183 a.Val.SetUint64(0) 184 } 185 } 186 187 func Fconv(fvp *Mpflt, flag int) string { 188 if flag&obj.FmtSharp == 0 { 189 return fvp.Val.Format('b', 0) 190 } 191 192 // use decimal format for error messages 193 194 // determine sign 195 f := &fvp.Val 196 var sign string 197 if fvp.Val.Signbit() { 198 sign = "-" 199 f = new(big.Float).Abs(f) 200 } else if flag&obj.FmtSign != 0 { 201 sign = "+" 202 } 203 204 // Use fmt formatting if in float64 range (common case). 205 if x, _ := f.Float64(); !math.IsInf(x, 0) { 206 return fmt.Sprintf("%s%.6g", sign, x) 207 } 208 209 // Out of float64 range. Do approximate manual to decimal 210 // conversion to avoid precise but possibly slow Float 211 // formatting. The exponent is > 0 since a negative out- 212 // of-range exponent would have underflowed and led to 0. 213 // f = mant * 2**exp 214 var mant big.Float 215 exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0 216 217 // approximate float64 mantissa m and decimal exponent d 218 // f ~ m * 10**d 219 m, _ := mant.Float64() // 0.5 <= m < 1.0 220 d := exp * (math.Ln2 / math.Ln10) // log_10(2) 221 222 // adjust m for truncated (integer) decimal exponent e 223 e := int64(d) 224 m *= math.Pow(10, d-float64(e)) 225 for m >= 10 { 226 m /= 10 227 e++ 228 } 229 230 return fmt.Sprintf("%s%.5fe+%d", sign, m, e) 231 }