On Tue, Nov 06, 2012 at 04:57:20PM -0430, Andres Perera wrote:

> On Tue, Nov 6, 2012 at 3:27 PM, Otto Moerbeek <o...@drijf.net> wrote:
> > 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.
> 
> i've lightly tested it against gnu bc and it works
> 
> i do have 2 small comments below

Fair enough. New diff.

        -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     7 Nov 2012 06:45:52 -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;
 
@@ -1005,11 +1011,9 @@ bmul_number(struct number *r, struct num
        bn_check(BN_mul(r->number, a->number, b->number, ctx));
        BN_CTX_free(ctx);
 
-       if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
-               r->scale = rscale;
-               normalize(r, max(bmachine.scale, max(ascale, bscale)));
-       } else
-               r->scale = rscale;
+       r->scale = rscale;
+       if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
+               normalize(r, max(scale, max(ascale, bscale)));
 }
 
 static void
@@ -1029,7 +1033,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 +1164,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 +1195,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 +1203,37 @@ 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 ascale, mscale;
+
+               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));
 
+               mscale = 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)) {
+                               mscale += ascale;
+                               bmul_number(r, r, a, mscale);
+                       }
                        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     7 Nov 2012 06:45:53 -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     7 Nov 2012 06:45:53 -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