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/compile/internal/big" 9 "cmd/internal/obj" 10 "fmt" 11 "math" 12 "strings" 13 ) 14 15 /// implements float arihmetic 16 17 func newMpflt() *Mpflt { 18 var a Mpflt 19 a.Val.SetPrec(Mpprec) 20 return &a 21 } 22 23 func Mpmovefixflt(a *Mpflt, b *Mpint) { 24 if b.Ovf { 25 // sign doesn't really matter but copy anyway 26 a.Val.SetInf(b.Val.Sign() < 0) 27 return 28 } 29 a.Val.SetInt(&b.Val) 30 } 31 32 func mpmovefltflt(a *Mpflt, b *Mpflt) { 33 a.Val.Set(&b.Val) 34 } 35 36 func mpaddfltflt(a *Mpflt, b *Mpflt) { 37 if Mpdebug { 38 fmt.Printf("\n%v + %v", a, b) 39 } 40 41 a.Val.Add(&a.Val, &b.Val) 42 43 if Mpdebug { 44 fmt.Printf(" = %v\n\n", a) 45 } 46 } 47 48 func mpaddcflt(a *Mpflt, c float64) { 49 var b Mpflt 50 51 Mpmovecflt(&b, c) 52 mpaddfltflt(a, &b) 53 } 54 55 func mpsubfltflt(a *Mpflt, b *Mpflt) { 56 if Mpdebug { 57 fmt.Printf("\n%v - %v", a, b) 58 } 59 60 a.Val.Sub(&a.Val, &b.Val) 61 62 if Mpdebug { 63 fmt.Printf(" = %v\n\n", a) 64 } 65 } 66 67 func mpmulfltflt(a *Mpflt, b *Mpflt) { 68 if Mpdebug { 69 fmt.Printf("%v\n * %v\n", a, b) 70 } 71 72 a.Val.Mul(&a.Val, &b.Val) 73 74 if Mpdebug { 75 fmt.Printf(" = %v\n\n", a) 76 } 77 } 78 79 func mpmulcflt(a *Mpflt, c float64) { 80 var b Mpflt 81 82 Mpmovecflt(&b, c) 83 mpmulfltflt(a, &b) 84 } 85 86 func mpdivfltflt(a *Mpflt, b *Mpflt) { 87 if Mpdebug { 88 fmt.Printf("%v\n / %v\n", a, b) 89 } 90 91 a.Val.Quo(&a.Val, &b.Val) 92 93 if Mpdebug { 94 fmt.Printf(" = %v\n\n", a) 95 } 96 } 97 98 func mpcmpfltflt(a *Mpflt, b *Mpflt) int { 99 return a.Val.Cmp(&b.Val) 100 } 101 102 func mpcmpfltc(b *Mpflt, c float64) int { 103 var a Mpflt 104 105 Mpmovecflt(&a, c) 106 return mpcmpfltflt(b, &a) 107 } 108 109 func mpgetflt(a *Mpflt) float64 { 110 x, _ := a.Val.Float64() 111 112 // check for overflow 113 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 114 Yyerror("mpgetflt ovf") 115 } 116 117 return x 118 } 119 120 func mpgetflt32(a *Mpflt) float64 { 121 x32, _ := a.Val.Float32() 122 x := float64(x32) 123 124 // check for overflow 125 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 126 Yyerror("mpgetflt32 ovf") 127 } 128 129 return x 130 } 131 132 func Mpmovecflt(a *Mpflt, c float64) { 133 if Mpdebug { 134 fmt.Printf("\nconst %g", c) 135 } 136 137 a.Val.SetFloat64(c) 138 139 if Mpdebug { 140 fmt.Printf(" = %v\n", a) 141 } 142 } 143 144 func mpnegflt(a *Mpflt) { 145 a.Val.Neg(&a.Val) 146 } 147 148 // 149 // floating point input 150 // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] 151 // 152 func mpatoflt(a *Mpflt, as string) { 153 for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { 154 as = as[1:] 155 } 156 157 // The spec requires accepting exponents that fit in int32. 158 // Don't accept much more than that. 159 // Count digits in exponent and stop early if there are too many. 160 if i := strings.Index(as, "e"); i >= 0 { 161 i++ 162 if i < len(as) && (as[i] == '-' || as[i] == '+') { 163 i++ 164 } 165 for i < len(as) && as[i] == '0' { 166 i++ 167 } 168 // TODO(rsc): This should be > 10, because we're supposed 169 // to accept any signed 32-bit int as an exponent. 170 // But that's not working terribly well, so we deviate from the 171 // spec in order to make sure that what we accept works. 172 // We can remove this restriction once those larger exponents work. 173 // See golang.org/issue/11326 and test/fixedbugs/issue11326*.go. 174 if len(as)-i > 8 { 175 Yyerror("malformed constant: %s (exponent too large)", as) 176 a.Val.SetUint64(0) 177 return 178 } 179 } 180 181 f, ok := a.Val.SetString(as) 182 if !ok { 183 // At the moment we lose precise error cause; 184 // the old code additionally distinguished between: 185 // - malformed hex constant 186 // - decimal point in hex constant 187 // - constant exponent out of range 188 // - decimal point and binary point in constant 189 // TODO(gri) use different conversion function or check separately 190 Yyerror("malformed constant: %s", as) 191 a.Val.SetUint64(0) 192 return 193 } 194 195 if f.IsInf() { 196 Yyerror("constant too large: %s", as) 197 a.Val.SetUint64(0) 198 return 199 } 200 } 201 202 func (f *Mpflt) String() string { 203 return Fconv(f, 0) 204 } 205 206 func Fconv(fvp *Mpflt, flag int) string { 207 if flag&obj.FmtSharp == 0 { 208 return fvp.Val.Text('b', 0) 209 } 210 211 // use decimal format for error messages 212 213 // determine sign 214 f := &fvp.Val 215 var sign string 216 if fvp.Val.Signbit() { 217 sign = "-" 218 f = new(big.Float).Abs(f) 219 } else if flag&obj.FmtSign != 0 { 220 sign = "+" 221 } 222 223 // Use fmt formatting if in float64 range (common case). 224 if x, _ := f.Float64(); !math.IsInf(x, 0) { 225 return fmt.Sprintf("%s%.6g", sign, x) 226 } 227 228 // Out of float64 range. Do approximate manual to decimal 229 // conversion to avoid precise but possibly slow Float 230 // formatting. The exponent is > 0 since a negative out- 231 // of-range exponent would have underflowed and led to 0. 232 // f = mant * 2**exp 233 var mant big.Float 234 exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0 235 236 // approximate float64 mantissa m and decimal exponent d 237 // f ~ m * 10**d 238 m, _ := mant.Float64() // 0.5 <= m < 1.0 239 d := exp * (math.Ln2 / math.Ln10) // log_10(2) 240 241 // adjust m for truncated (integer) decimal exponent e 242 e := int64(d) 243 m *= math.Pow(10, d-float64(e)) 244 for m >= 10 { 245 m /= 10 246 e++ 247 } 248 249 return fmt.Sprintf("%s%.5fe+%d", sign, m, e) 250 } 251