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 "go.h"
6
7 /// uses arithmetic
8
9 int
10 mpcmpfixflt(Mpint *a, Mpflt *b)
11 {
12 char buf[500];
13 Mpflt c;
14
15 snprint(buf, sizeof(buf), "%B", a);
16 mpatoflt(&c, buf);
17 return mpcmpfltflt(&c, b);
18 }
19
20 int
21 mpcmpfltfix(Mpflt *a, Mpint *b)
22 {
23 char buf[500];
24 Mpflt c;
25
26 snprint(buf, sizeof(buf), "%B", b);
27 mpatoflt(&c, buf);
28 return mpcmpfltflt(a, &c);
29 }
30
31 int
32 mpcmpfixfix(Mpint *a, Mpint *b)
33 {
34 Mpint c;
35
36 mpmovefixfix(&c, a);
37 mpsubfixfix(&c, b);
38 return mptestfix(&c);
39 }
40
41 int
42 mpcmpfixc(Mpint *b, vlong c)
43 {
44 Mpint a;
45
46 mpmovecfix(&a, c);
47 return mpcmpfixfix(&a, b);
48 }
49
50 int
51 mpcmpfltflt(Mpflt *a, Mpflt *b)
52 {
53 Mpflt c;
54
55 mpmovefltflt(&c, a);
56 mpsubfltflt(&c, b);
57 return mptestflt(&c);
58 }
59
60 int
61 mpcmpfltc(Mpflt *b, double c)
62 {
63 Mpflt a;
64
65 mpmovecflt(&a, c);
66 return mpcmpfltflt(&a, b);
67 }
68
69 void
70 mpsubfixfix(Mpint *a, Mpint *b)
71 {
72 mpnegfix(a);
73 mpaddfixfix(a, b);
74 mpnegfix(a);
75 }
76
77 void
78 mpsubfltflt(Mpflt *a, Mpflt *b)
79 {
80 mpnegflt(a);
81 mpaddfltflt(a, b);
82 mpnegflt(a);
83 }
84
85 void
86 mpaddcfix(Mpint *a, vlong c)
87 {
88 Mpint b;
89
90 mpmovecfix(&b, c);
91 mpaddfixfix(a, &b);
92 }
93
94 void
95 mpaddcflt(Mpflt *a, double c)
96 {
97 Mpflt b;
98
99 mpmovecflt(&b, c);
100 mpaddfltflt(a, &b);
101 }
102
103 void
104 mpmulcfix(Mpint *a, vlong c)
105 {
106 Mpint b;
107
108 mpmovecfix(&b, c);
109 mpmulfixfix(a, &b);
110 }
111
112 void
113 mpmulcflt(Mpflt *a, double c)
114 {
115 Mpflt b;
116
117 mpmovecflt(&b, c);
118 mpmulfltflt(a, &b);
119 }
120
121 void
122 mpdivfixfix(Mpint *a, Mpint *b)
123 {
124 Mpint q, r;
125
126 mpdivmodfixfix(&q, &r, a, b);
127 mpmovefixfix(a, &q);
128 }
129
130 void
131 mpmodfixfix(Mpint *a, Mpint *b)
132 {
133 Mpint q, r;
134
135 mpdivmodfixfix(&q, &r, a, b);
136 mpmovefixfix(a, &r);
137 }
138
139 void
140 mpcomfix(Mpint *a)
141 {
142 Mpint b;
143
144 mpmovecfix(&b, 1);
145 mpnegfix(a);
146 mpsubfixfix(a, &b);
147 }
148
149 void
150 mpmovefixflt(Mpflt *a, Mpint *b)
151 {
152 a->val = *b;
153 a->exp = 0;
154 mpnorm(a);
155 }
156
157 // convert (truncate) b to a.
158 // return -1 (but still convert) if b was non-integer.
159 static int
160 mpexactfltfix(Mpint *a, Mpflt *b)
161 {
162 Mpflt f;
163
164 *a = b->val;
165 mpshiftfix(a, b->exp);
166 if(b->exp < 0) {
167 f.val = *a;
168 f.exp = 0;
169 mpnorm(&f);
170 if(mpcmpfltflt(b, &f) != 0)
171 return -1;
172 }
173 return 0;
174 }
175
176 int
177 mpmovefltfix(Mpint *a, Mpflt *b)
178 {
179 Mpflt f;
180 int i;
181
182 if(mpexactfltfix(a, b) == 0)
183 return 0;
184
185 // try rounding down a little
186 f = *b;
187 f.val.a[0] = 0;
188 if(mpexactfltfix(a, &f) == 0)
189 return 0;
190
191 // try rounding up a little
192 for(i=1; i<Mpprec; i++) {
193 f.val.a[i]++;
194 if(f.val.a[i] != Mpbase)
195 break;
196 f.val.a[i] = 0;
197 }
198 mpnorm(&f);
199 if(mpexactfltfix(a, &f) == 0)
200 return 0;
201
202 return -1;
203 }
204
205 void
206 mpmovefixfix(Mpint *a, Mpint *b)
207 {
208 *a = *b;
209 }
210
211 void
212 mpmovefltflt(Mpflt *a, Mpflt *b)
213 {
214 *a = *b;
215 }
216
217 static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
218 static void
219 mppow10flt(Mpflt *a, int p)
220 {
221 if(p < 0)
222 abort();
223 if(p < nelem(tab)) {
224 mpmovecflt(a, tab[p]);
225 return;
226 }
227 mppow10flt(a, p>>1);
228 mpmulfltflt(a, a);
229 if(p & 1)
230 mpmulcflt(a, 10);
231 }
232
233 //
234 // floating point input
235 // required syntax is [+-]d*[.]d*[e[+-]d*]
236 //
237 void
238 mpatoflt(Mpflt *a, char *as)
239 {
240 Mpflt b;
241 int dp, c, f, ef, ex, eb;
242 char *s;
243
244 s = as;
245 dp = 0; /* digits after decimal point */
246 f = 0; /* sign */
247 ex = 0; /* exponent */
248 eb = 0; /* binary point */
249
250 mpmovecflt(a, 0.0);
251 for(;;) {
252 switch(c = *s++) {
253 default:
254 goto bad;
255
256 case '-':
257 f = 1;
258
259 case ' ':
260 case '\t':
261 case '+':
262 continue;
263
264 case '.':
265 dp = 1;
266 continue;
267
268 case '1':
269 case '2':
270 case '3':
271 case '4':
272 case '5':
273 case '6':
274 case '7':
275 case '8':
276 case '9':
277 case '0':
278 mpmulcflt(a, 10);
279 mpaddcflt(a, c-'0');
280 if(dp)
281 dp++;
282 continue;
283
284 case 'P':
285 case 'p':
286 eb = 1;
287
288 case 'E':
289 case 'e':
290 ex = 0;
291 ef = 0;
292 for(;;) {
293 c = *s++;
294 if(c == '+' || c == ' ' || c == '\t')
295 continue;
296 if(c == '-') {
297 ef = 1;
298 continue;
299 }
300 if(c >= '0' && c <= '9') {
301 ex = ex*10 + (c-'0');
302 if(ex > 1e8) {
303 yyerror("exponent out of range");
304 errorexit();
305 }
306 continue;
307 }
308 break;
309 }
310 if(ef)
311 ex = -ex;
312
313 case 0:
314 break;
315 }
316 break;
317 }
318
319 if(eb) {
320 if(dp)
321 goto bad;
322 a->exp += ex;
323 goto out;
324 }
325
326 if(dp)
327 dp--;
328 if(mpcmpfltc(a, 0.0) != 0) {
329 if(ex >= dp) {
330 mppow10flt(&b, ex-dp);
331 mpmulfltflt(a, &b);
332 } else {
333 mppow10flt(&b, dp-ex);
334 mpdivfltflt(a, &b);
335 }
336 }
337
338 out:
339 if(f)
340 mpnegflt(a);
341 return;
342
343 bad:
344 yyerror("set ovf in mpatof");
345 mpmovecflt(a, 0.0);
346 }
347
348 //
349 // fixed point input
350 // required syntax is [+-][0[x]]d*
351 //
352 void
353 mpatofix(Mpint *a, char *as)
354 {
355 int c, f;
356 char *s;
357
358 s = as;
359 f = 0;
360 mpmovecfix(a, 0);
361
362 c = *s++;
363 switch(c) {
364 case '-':
365 f = 1;
366
367 case '+':
368 c = *s++;
369 if(c != '0')
370 break;
371
372 case '0':
373 goto oct;
374 }
375
376 while(c) {
377 if(c >= '0' && c <= '9') {
378 mpmulcfix(a, 10);
379 mpaddcfix(a, c-'0');
380 c = *s++;
381 continue;
382 }
383 goto bad;
384 }
385 goto out;
386
387 oct:
388 c = *s++;
389 if(c == 'x' || c == 'X')
390 goto hex;
391 while(c) {
392 if(c >= '0' && c <= '7') {
393 mpmulcfix(a, 8);
394 mpaddcfix(a, c-'0');
395 c = *s++;
396 continue;
397 }
398 goto bad;
399 }
400 goto out;
401
402 hex:
403 c = *s++;
404 while(c) {
405 if(c >= '0' && c <= '9') {
406 mpmulcfix(a, 16);
407 mpaddcfix(a, c-'0');
408 c = *s++;
409 continue;
410 }
411 if(c >= 'a' && c <= 'f') {
412 mpmulcfix(a, 16);
413 mpaddcfix(a, c+10-'a');
414 c = *s++;
415 continue;
416 }
417 if(c >= 'A' && c <= 'F') {
418 mpmulcfix(a, 16);
419 mpaddcfix(a, c+10-'A');
420 c = *s++;
421 continue;
422 }
423 goto bad;
424 }
425
426 out:
427 if(f)
428 mpnegfix(a);
429 return;
430
431 bad:
432 yyerror("set ovf in mpatov: %s", as);
433 mpmovecfix(a, 0);
434 }
435
436 int
437 Bconv(Fmt *fp)
438 {
439 char buf[500], *p;
440 Mpint *xval, q, r, ten;
441 int f;
442
443 xval = va_arg(fp->args, Mpint*);
444 mpmovefixfix(&q, xval);
445 f = 0;
446 if(mptestfix(&q) < 0) {
447 f = 1;
448 mpnegfix(&q);
449 }
450 mpmovecfix(&ten, 10);
451
452 p = &buf[sizeof(buf)];
453 *--p = 0;
454 for(;;) {
455 mpdivmodfixfix(&q, &r, &q, &ten);
456 *--p = mpgetfix(&r) + '0';
457 if(mptestfix(&q) <= 0)
458 break;
459 }
460 if(f)
461 *--p = '-';
462 return fmtstrcpy(fp, p);
463 }
464
465 int
466 Fconv(Fmt *fp)
467 {
468 char buf[500];
469 Mpflt *fvp, fv;
470 double d;
471
472 fvp = va_arg(fp->args, Mpflt*);
473 if(fp->flags & FmtSharp) {
474 // alternate form - decimal for error messages.
475 // for well in range, convert to double and use print's %g
476 if(-900 < fvp->exp && fvp->exp < 900) {
477 d = mpgetflt(fvp);
478 if(d >= 0 && (fp->flags & FmtSign))
479 fmtprint(fp, "+");
480 return fmtprint(fp, "%g", d);
481 }
482 // TODO(rsc): for well out of range, print
483 // an approximation like 1.234e1000
484 }
485
486 if(sigfig(fvp) == 0) {
487 snprint(buf, sizeof(buf), "0p+0");
488 goto out;
489 }
490 fv = *fvp;
491
492 while(fv.val.a[0] == 0) {
493 mpshiftfix(&fv.val, -Mpscale);
494 fv.exp += Mpscale;
495 }
496 while((fv.val.a[0]&1) == 0) {
497 mpshiftfix(&fv.val, -1);
498 fv.exp += 1;
499 }
500
501 if(fv.exp >= 0) {
502 snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
503 goto out;
504 }
505 snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
506
507 out:
508 return fmtstrcpy(fp, buf);
509 }