diff options
Diffstat (limited to 'src/cmd/gc/mparith1.c')
-rw-r--r-- | src/cmd/gc/mparith1.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index e25044a8b..1519caec7 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -65,7 +65,7 @@ mpcmpfltc(Mpflt *b, double c) Mpflt a; mpmovecflt(&a, c); - return mpcmpfltflt(&a, b); + return mpcmpfltflt(b, &a); } void @@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as) if(eb) { if(dp) goto bad; - a->exp += ex; + mpsetexp(a, a->exp+ex); goto out; } @@ -427,8 +427,14 @@ mpatoflt(Mpflt *a, char *as) mppow10flt(&b, ex-dp); mpmulfltflt(a, &b); } else { - mppow10flt(&b, dp-ex); - mpdivfltflt(a, &b); + // 4 approximates least_upper_bound(log2(10)). + if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) { + mpmovecflt(a, 0.0); + } + else { + mppow10flt(&b, dp-ex); + mpdivfltflt(a, &b); + } } } @@ -573,20 +579,40 @@ Fconv(Fmt *fp) { char buf[500]; Mpflt *fvp, fv; - double d; + double d, dexp; + int exp; fvp = va_arg(fp->args, Mpflt*); if(fp->flags & FmtSharp) { // alternate form - decimal for error messages. // for well in range, convert to double and use print's %g - if(-900 < fvp->exp && fvp->exp < 900) { + exp = fvp->exp + sigfig(fvp)*Mpscale; + if(-900 < exp && exp < 900) { d = mpgetflt(fvp); if(d >= 0 && (fp->flags & FmtSign)) fmtprint(fp, "+"); - return fmtprint(fp, "%g", d); + return fmtprint(fp, "%g", d, exp, fvp); + } + + // very out of range. compute decimal approximation by hand. + // decimal exponent + dexp = fvp->exp * 0.301029995663981195; // log_10(2) + exp = (int)dexp; + // decimal mantissa + fv = *fvp; + fv.val.neg = 0; + fv.exp = 0; + d = mpgetflt(&fv); + d *= pow(10, dexp-exp); + while(d >= 9.99995) { + d /= 10; + exp++; } - // TODO(rsc): for well out of range, print - // an approximation like 1.234e1000 + if(fvp->val.neg) + fmtprint(fp, "-"); + else if(fp->flags & FmtSign) + fmtprint(fp, "+"); + return fmtprint(fp, "%.5fe+%d", d, exp); } if(sigfig(fvp) == 0) { |