github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/cmd/gc/mparith3.c (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 #include <u.h> 6 #include <libc.h> 7 #include "go.h" 8 9 /* 10 * returns the leading non-zero 11 * word of the number 12 */ 13 int 14 sigfig(Mpflt *a) 15 { 16 int i; 17 18 for(i=Mpprec-1; i>=0; i--) 19 if(a->val.a[i] != 0) 20 break; 21 //print("sigfig %d %d\n", i-z+1, z); 22 return i+1; 23 } 24 25 /* 26 * sets the exponent. 27 * a too large exponent is an error. 28 * a too small exponent rounds the number to zero. 29 */ 30 void 31 mpsetexp(Mpflt *a, int exp) { 32 if((short)exp != exp) { 33 if(exp > 0) { 34 yyerror("float constant is too large"); 35 a->exp = 0x7fff; 36 } 37 else { 38 mpmovecflt(a, 0); 39 } 40 } 41 else { 42 a->exp = exp; 43 } 44 } 45 46 /* 47 * shifts the leading non-zero 48 * word of the number to Mpnorm 49 */ 50 void 51 mpnorm(Mpflt *a) 52 { 53 int s, os; 54 long x; 55 56 os = sigfig(a); 57 if(os == 0) { 58 // zero 59 a->exp = 0; 60 a->val.neg = 0; 61 return; 62 } 63 64 // this will normalize to the nearest word 65 x = a->val.a[os-1]; 66 s = (Mpnorm-os) * Mpscale; 67 68 // further normalize to the nearest bit 69 for(;;) { 70 x <<= 1; 71 if(x & Mpbase) 72 break; 73 s++; 74 if(x == 0) { 75 // this error comes from trying to 76 // convert an Inf or something 77 // where the initial x=0x80000000 78 s = (Mpnorm-os) * Mpscale; 79 break; 80 } 81 } 82 83 mpshiftfix(&a->val, s); 84 mpsetexp(a, a->exp-s); 85 } 86 87 /// implements float arihmetic 88 89 void 90 mpaddfltflt(Mpflt *a, Mpflt *b) 91 { 92 int sa, sb, s; 93 Mpflt c; 94 95 if(Mpdebug) 96 print("\n%F + %F", a, b); 97 98 sa = sigfig(a); 99 if(sa == 0) { 100 mpmovefltflt(a, b); 101 goto out; 102 } 103 104 sb = sigfig(b); 105 if(sb == 0) 106 goto out; 107 108 s = a->exp - b->exp; 109 if(s > 0) { 110 // a is larger, shift b right 111 mpmovefltflt(&c, b); 112 mpshiftfix(&c.val, -s); 113 mpaddfixfix(&a->val, &c.val, 0); 114 goto out; 115 } 116 if(s < 0) { 117 // b is larger, shift a right 118 mpshiftfix(&a->val, s); 119 mpsetexp(a, a->exp-s); 120 mpaddfixfix(&a->val, &b->val, 0); 121 goto out; 122 } 123 mpaddfixfix(&a->val, &b->val, 0); 124 125 out: 126 mpnorm(a); 127 if(Mpdebug) 128 print(" = %F\n\n", a); 129 } 130 131 void 132 mpmulfltflt(Mpflt *a, Mpflt *b) 133 { 134 int sa, sb; 135 136 if(Mpdebug) 137 print("%F\n * %F\n", a, b); 138 139 sa = sigfig(a); 140 if(sa == 0) { 141 // zero 142 a->exp = 0; 143 a->val.neg = 0; 144 return; 145 } 146 147 sb = sigfig(b); 148 if(sb == 0) { 149 // zero 150 mpmovefltflt(a, b); 151 return; 152 } 153 154 mpmulfract(&a->val, &b->val); 155 mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1); 156 157 mpnorm(a); 158 if(Mpdebug) 159 print(" = %F\n\n", a); 160 } 161 162 void 163 mpdivfltflt(Mpflt *a, Mpflt *b) 164 { 165 int sa, sb; 166 Mpflt c; 167 168 if(Mpdebug) 169 print("%F\n / %F\n", a, b); 170 171 sb = sigfig(b); 172 if(sb == 0) { 173 // zero and ovfl 174 a->exp = 0; 175 a->val.neg = 0; 176 a->val.ovf = 1; 177 yyerror("constant division by zero"); 178 return; 179 } 180 181 sa = sigfig(a); 182 if(sa == 0) { 183 // zero 184 a->exp = 0; 185 a->val.neg = 0; 186 return; 187 } 188 189 // adjust b to top 190 mpmovefltflt(&c, b); 191 mpshiftfix(&c.val, Mpscale); 192 193 // divide 194 mpdivfract(&a->val, &c.val); 195 mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1); 196 197 mpnorm(a); 198 if(Mpdebug) 199 print(" = %F\n\n", a); 200 } 201 202 static double 203 mpgetfltN(Mpflt *a, int prec, int bias) 204 { 205 int s, i, e, minexp; 206 uvlong v; 207 double f; 208 209 if(a->val.ovf && nsavederrors+nerrors == 0) 210 yyerror("mpgetflt ovf"); 211 212 s = sigfig(a); 213 if(s == 0) 214 return 0; 215 216 if(s != Mpnorm) { 217 yyerror("mpgetflt norm"); 218 mpnorm(a); 219 } 220 221 while((a->val.a[Mpnorm-1] & Mpsign) == 0) { 222 mpshiftfix(&a->val, 1); 223 mpsetexp(a, a->exp-1); // can set 'a' to zero 224 s = sigfig(a); 225 if(s == 0) 226 return 0; 227 } 228 229 // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong 230 s = prec+2; 231 v = 0; 232 for(i=Mpnorm-1; s>=Mpscale; i--) { 233 v = (v<<Mpscale) | a->val.a[i]; 234 s -= Mpscale; 235 } 236 if(s > 0) { 237 v = (v<<s) | (a->val.a[i]>>(Mpscale-s)); 238 if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0) 239 v |= 1; 240 i--; 241 } 242 for(; i >= 0; i--) { 243 if(a->val.a[i] != 0) 244 v |= 1; 245 } 246 247 // gradual underflow 248 e = Mpnorm*Mpscale + a->exp - prec; 249 minexp = bias+1-prec+1; 250 if(e < minexp) { 251 s = minexp - e; 252 if(s > prec+1) 253 s = prec+1; 254 if((v & ((1ULL<<s)-1)) != 0) 255 v |= 1ULL<<s; 256 v >>= s; 257 e = minexp; 258 } 259 260 // round to even 261 v |= (v&4)>>2; 262 v += v&1; 263 v >>= 2; 264 265 f = (double)(v); 266 f = ldexp(f, e); 267 268 if(a->val.neg) 269 f = -f; 270 271 return f; 272 } 273 274 double 275 mpgetflt(Mpflt *a) 276 { 277 return mpgetfltN(a, 53, -1023); 278 } 279 280 double 281 mpgetflt32(Mpflt *a) 282 { 283 return mpgetfltN(a, 24, -127); 284 } 285 286 void 287 mpmovecflt(Mpflt *a, double c) 288 { 289 int i; 290 double f; 291 long l; 292 293 if(Mpdebug) 294 print("\nconst %g", c); 295 mpmovecfix(&a->val, 0); 296 a->exp = 0; 297 if(c == 0) 298 goto out; 299 if(c < 0) { 300 a->val.neg = 1; 301 c = -c; 302 } 303 304 f = frexp(c, &i); 305 a->exp = i; 306 307 for(i=0; i<10; i++) { 308 f = f*Mpbase; 309 l = floor(f); 310 f = f - l; 311 a->exp -= Mpscale; 312 a->val.a[0] = l; 313 if(f == 0) 314 break; 315 mpshiftfix(&a->val, Mpscale); 316 } 317 318 out: 319 mpnorm(a); 320 if(Mpdebug) 321 print(" = %F\n", a); 322 } 323 324 void 325 mpnegflt(Mpflt *a) 326 { 327 a->val.neg ^= 1; 328 } 329 330 int 331 mptestflt(Mpflt *a) 332 { 333 int s; 334 335 if(Mpdebug) 336 print("\n%F?", a); 337 s = sigfig(a); 338 if(s != 0) { 339 s = +1; 340 if(a->val.neg) 341 s = -1; 342 } 343 if(Mpdebug) 344 print(" = %d\n", s); 345 return s; 346 }