summaryrefslogtreecommitdiff
path: root/src/cmd/gc/mparith1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/mparith1.c')
-rw-r--r--src/cmd/gc/mparith1.c44
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) {