github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/compile/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/compile/internal/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", a, b) 38 } 39 40 a.Val.Add(&a.Val, &b.Val) 41 42 if Mpdebug { 43 fmt.Printf(" = %v\n\n", a) 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", a, b) 57 } 58 59 a.Val.Sub(&a.Val, &b.Val) 60 61 if Mpdebug { 62 fmt.Printf(" = %v\n\n", a) 63 } 64 } 65 66 func mpmulfltflt(a *Mpflt, b *Mpflt) { 67 if Mpdebug { 68 fmt.Printf("%v\n * %v\n", a, b) 69 } 70 71 a.Val.Mul(&a.Val, &b.Val) 72 73 if Mpdebug { 74 fmt.Printf(" = %v\n\n", a) 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", a, b) 88 } 89 90 a.Val.Quo(&a.Val, &b.Val) 91 92 if Mpdebug { 93 fmt.Printf(" = %v\n\n", a) 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 mpgetflt(a *Mpflt) float64 { 109 x, _ := a.Val.Float64() 110 111 // check for overflow 112 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 113 Yyerror("mpgetflt ovf") 114 } 115 116 return x + 0 // avoid -0 (should not be needed, but be conservative) 117 } 118 119 func mpgetflt32(a *Mpflt) float64 { 120 x32, _ := a.Val.Float32() 121 x := float64(x32) 122 123 // check for overflow 124 if math.IsInf(x, 0) && nsavederrors+nerrors == 0 { 125 Yyerror("mpgetflt32 ovf") 126 } 127 128 return x + 0 // avoid -0 (should not be needed, but be conservative) 129 } 130 131 func Mpmovecflt(a *Mpflt, c float64) { 132 if Mpdebug { 133 fmt.Printf("\nconst %g", c) 134 } 135 136 // convert -0 to 0 137 if c == 0 { 138 c = 0 139 } 140 a.Val.SetFloat64(c) 141 142 if Mpdebug { 143 fmt.Printf(" = %v\n", a) 144 } 145 } 146 147 func mpnegflt(a *Mpflt) { 148 // avoid -0 149 if a.Val.Sign() != 0 { 150 a.Val.Neg(&a.Val) 151 } 152 } 153 154 // 155 // floating point input 156 // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] 157 // 158 func mpatoflt(a *Mpflt, as string) { 159 for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { 160 as = as[1:] 161 } 162 163 f, ok := a.Val.SetString(as) 164 if !ok { 165 // At the moment we lose precise error cause; 166 // the old code additionally distinguished between: 167 // - malformed hex constant 168 // - decimal point in hex constant 169 // - constant exponent out of range 170 // - decimal point and binary point in constant 171 // TODO(gri) use different conversion function or check separately 172 Yyerror("malformed constant: %s", as) 173 a.Val.SetFloat64(0) 174 return 175 } 176 177 if f.IsInf() { 178 Yyerror("constant too large: %s", as) 179 a.Val.SetFloat64(0) 180 return 181 } 182 183 // -0 becomes 0 184 if f.Sign() == 0 && f.Signbit() { 185 a.Val.SetFloat64(0) 186 } 187 } 188 189 func (f *Mpflt) String() string { 190 return Fconv(f, 0) 191 } 192 193 func Fconv(fvp *Mpflt, flag int) string { 194 if flag&obj.FmtSharp == 0 { 195 return fvp.Val.Text('b', 0) 196 } 197 198 // use decimal format for error messages 199 200 // determine sign 201 f := &fvp.Val 202 var sign string 203 if f.Sign() < 0 { 204 sign = "-" 205 f = new(big.Float).Abs(f) 206 } else if flag&obj.FmtSign != 0 { 207 sign = "+" 208 } 209 210 // Don't try to convert infinities (will not terminate). 211 if f.IsInf() { 212 return sign + "Inf" 213 } 214 215 // Use fmt formatting if in float64 range (common case). 216 if x, _ := f.Float64(); !math.IsInf(x, 0) { 217 return fmt.Sprintf("%s%.6g", sign, x) 218 } 219 220 // Out of float64 range. Do approximate manual to decimal 221 // conversion to avoid precise but possibly slow Float 222 // formatting. The exponent is > 0 since a negative out- 223 // of-range exponent would have underflowed and led to 0. 224 // f = mant * 2**exp 225 var mant big.Float 226 exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0 227 228 // approximate float64 mantissa m and decimal exponent d 229 // f ~ m * 10**d 230 m, _ := mant.Float64() // 0.5 <= m < 1.0 231 d := exp * (math.Ln2 / math.Ln10) // log_10(2) 232 233 // adjust m for truncated (integer) decimal exponent e 234 e := int64(d) 235 m *= math.Pow(10, d-float64(e)) 236 for m >= 10 { 237 m /= 10 238 e++ 239 } 240 241 return fmt.Sprintf("%s%.5fe+%d", sign, m, e) 242 }