Hi,

And here's a diff to repair ^, whcih now produces correct results for
things like 

(dc)    0.1 _1 ^p
or 
(bc)    0.1 ^ -1

The diff is against very current, so beware.

Please test. I have some regress test updates for dc as well. t9 turns
out to be a wrong test (computation of 2.1 ^ 500). That is fixed with
this diff as well. 

        -Otto

Index: bcode.c
===================================================================
RCS file: /cvs/src/usr.bin/dc/bcode.c,v
retrieving revision 1.44
diff -u -p -r1.44 bcode.c
--- bcode.c     6 Nov 2012 16:00:05 -0000       1.44
+++ bcode.c     6 Nov 2012 19:42:07 -0000
@@ -257,6 +257,12 @@ init_bmachine(bool extended_registers)
        (void)signal(SIGINT, sighandler);
 }
 
+u_int
+bmachine_scale(void)
+{
+       return bmachine.scale;
+}
+
 /* Reset the things needed before processing a (new) file */
 void
 reset_bmachine(struct source *src)
@@ -991,7 +997,7 @@ bsub(void)
 }
 
 void
-bmul_number(struct number *r, struct number *a, struct number *b)
+bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
 {
        BN_CTX          *ctx;
 
@@ -1007,7 +1013,7 @@ bmul_number(struct number *r, struct num
 
        if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
                r->scale = rscale;
-               normalize(r, max(bmachine.scale, max(ascale, bscale)));
+               normalize(r, max(scale, max(ascale, bscale)));
        } else
                r->scale = rscale;
 }
@@ -1029,7 +1035,7 @@ bmul(void)
        }
 
        r = new_number();
-       bmul_number(r, a, b);
+       bmul_number(r, a, b, bmachine.scale);
 
        push_number(r);
        free_number(a);
@@ -1160,7 +1166,7 @@ bexp(void)
        struct number   *a, *p;
        struct number   *r;
        bool            neg;
-       u_int           scale;
+       u_int           rscale;
 
        p = pop_number();
        if (p == NULL) {
@@ -1191,7 +1197,7 @@ bexp(void)
        if (BN_is_negative(p->number)) {
                neg = true;
                negate(p);
-               scale = bmachine.scale;
+               rscale = bmachine.scale;
        } else {
                /* Posix bc says min(a.scale * b, max(a.scale, scale) */
                u_long  b;
@@ -1199,30 +1205,35 @@ bexp(void)
 
                b = BN_get_word(p->number);
                m = max(a->scale, bmachine.scale);
-               scale = a->scale * (u_int)b;
-               if (scale > m || (a->scale > 0 && (b == BN_MASK2 ||
+               rscale = a->scale * (u_int)b;
+               if (rscale > m || (a->scale > 0 && (b == BN_MASK2 ||
                    b > UINT_MAX)))
-                       scale = m;
+                       rscale = m;
        }
 
        if (BN_is_zero(p->number)) {
                r = new_number();
                bn_check(BN_one(r->number));
-               normalize(r, scale);
+               normalize(r, rscale);
        } else {
+               u_int scale, ascale = a->scale;
                while (!BN_is_bit_set(p->number, 0)) {
-                       bmul_number(a, a, a);
+                       ascale *= 2;
+                       bmul_number(a, a, a, ascale);
                        bn_check(BN_rshift1(p->number, p->number));
                }
 
                r = dup_number(a);
-               normalize(r, scale);
                bn_check(BN_rshift1(p->number, p->number));
 
+               scale = ascale;
                while (!BN_is_zero(p->number)) {
-                       bmul_number(a, a, a);
-                       if (BN_is_bit_set(p->number, 0))
-                               bmul_number(r, r, a);
+                       ascale *= 2;
+                       bmul_number(a, a, a, ascale);
+                       if (BN_is_bit_set(p->number, 0)) {
+                               scale += ascale;
+                               bmul_number(r, r, a, scale);
+                       }
                        bn_check(BN_rshift1(p->number, p->number));
                }
 
@@ -1235,8 +1246,7 @@ bexp(void)
                        bn_check(BN_one(one));
                        ctx = BN_CTX_new();
                        bn_checkp(ctx);
-                       scale_number(one, r->scale + scale);
-                       normalize(r, scale);
+                       scale_number(one, r->scale + rscale);
 
                        if (BN_is_zero(r->number))
                                warnx("divide by zero");
@@ -1245,8 +1255,9 @@ bexp(void)
                                    r->number, ctx));
                        BN_free(one);
                        BN_CTX_free(ctx);
+                       r->scale = rscale;
                } else
-                       normalize(r, scale);
+                       normalize(r, rscale);
        }
        push_number(r);
        free_number(a);
Index: bcode.h
===================================================================
RCS file: /cvs/src/usr.bin/dc/bcode.h,v
retrieving revision 1.6
diff -u -p -r1.6 bcode.h
--- bcode.h     6 Nov 2012 16:00:05 -0000       1.6
+++ bcode.h     6 Nov 2012 19:42:07 -0000
@@ -85,6 +85,7 @@ struct source {
 
 void                   init_bmachine(bool);
 void                   reset_bmachine(struct source *);
+u_int                  bmachine_scale(void);
 void                   scale_number(BIGNUM *, int);
 void                   normalize(struct number *, u_int);
 void                   eval(void);
@@ -93,4 +94,4 @@ void                  pbn(const char *, const BIGNUM *)
 void                   negate(struct number *);
 void                   split_number(const struct number *, BIGNUM *, BIGNUM *);
 void                   bmul_number(struct number *, struct number *,
-                           struct number *);
+                           struct number *, u_int scale);
Index: inout.c
===================================================================
RCS file: /cvs/src/usr.bin/dc/inout.c,v
retrieving revision 1.16
diff -u -p -r1.16 inout.c
--- inout.c     6 Nov 2012 16:00:05 -0000       1.16
+++ inout.c     6 Nov 2012 19:42:07 -0000
@@ -348,7 +348,8 @@ printnumber(FILE *f, const struct number
                                putcharwrap(f, ' ');
                        i = 1;
 
-                       bmul_number(fract_part, fract_part, num_base);
+                       bmul_number(fract_part, fract_part, num_base,
+                           bmachine_scale());
                        split_number(fract_part, int_part->number, NULL);
                        rem = BN_get_word(int_part->number);
                        p = get_digit(rem, digits, base);

Reply via email to