github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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 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 129 } 130 131 func Mpmovecflt(a *Mpflt, c float64) { 132 if Mpdebug { 133 fmt.Printf("\nconst %g", c) 134 } 135 136 a.Val.SetFloat64(c) 137 138 if Mpdebug { 139 fmt.Printf(" = %v\n", a) 140 } 141 } 142 143 func mpnegflt(a *Mpflt) { 144 a.Val.Neg(&a.Val) 145 } 146 147 // 148 // floating point input 149 // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] 150 // 151 func mpatoflt(a *Mpflt, as string) { 152 for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { 153 as = as[1:] 154 } 155 156 f, ok := a.Val.SetString(as) 157 if !ok { 158 // At the moment we lose precise error cause; 159 // the old code additionally distinguished between: 160 // - malformed hex constant 161 // - decimal point in hex constant 162 // - constant exponent out of range 163 // - decimal point and binary point in constant 164 // TODO(gri) use different conversion function or check separately 165 Yyerror("malformed constant: %s", as) 166 a.Val.SetUint64(0) 167 return 168 } 169 170 if f.IsInf() { 171 Yyerror("constant too large: %s", as) 172 a.Val.SetUint64(0) 173 return 174 } 175 } 176 177 func (f *Mpflt) String() string { 178 return Fconv(f, 0) 179 } 180 181 func Fconv(fvp *Mpflt, flag int) string { 182 if flag&obj.FmtSharp == 0 { 183 return fvp.Val.Text('b', 0) 184 } 185 186 // use decimal format for error messages 187 188 // determine sign 189 f := &fvp.Val 190 var sign string 191 if fvp.Val.Signbit() { 192 sign = "-" 193 f = new(big.Float).Abs(f) 194 } else if flag&obj.FmtSign != 0 { 195 sign = "+" 196 } 197 198 // Use fmt formatting if in float64 range (common case). 199 if x, _ := f.Float64(); !math.IsInf(x, 0) { 200 return fmt.Sprintf("%s%.6g", sign, x) 201 } 202 203 // Out of float64 range. Do approximate manual to decimal 204 // conversion to avoid precise but possibly slow Float 205 // formatting. The exponent is > 0 since a negative out- 206 // of-range exponent would have underflowed and led to 0. 207 // f = mant * 2**exp 208 var mant big.Float 209 exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0 210 211 // approximate float64 mantissa m and decimal exponent d 212 // f ~ m * 10**d 213 m, _ := mant.Float64() // 0.5 <= m < 1.0 214 d := exp * (math.Ln2 / math.Ln10) // log_10(2) 215 216 // adjust m for truncated (integer) decimal exponent e 217 e := int64(d) 218 m *= math.Pow(10, d-float64(e)) 219 for m >= 10 { 220 m /= 10 221 e++ 222 } 223 224 return fmt.Sprintf("%s%.5fe+%d", sign, m, e) 225 }