dc(1) exp improvements

2012-11-06 Thread Otto Moerbeek
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 -   1.44
+++ bcode.c 6 Nov 2012 19:42:07 -
@@ -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;
boolneg;
-   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 

Re: dc(1) exp improvements

2012-11-06 Thread Andres Perera
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


 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 -   1.44
 +++ bcode.c 6 Nov 2012 19:42:07 -
 @@ -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;

the function unconditionally sets r-scale to rscale, but the
operation is duplicated across `if' bodies. interpreting a diff for
the function is difficult because the intent is unclear

  }
 @@ -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;
 boolneg;
 -   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;

`scale' should be renamed for clarity to signify that it's an
accumulator for `ascale'. at its current state, not being prefixed by
a letter that is, `scale' looks more important than it is



Re: dc(1) exp improvements

2012-11-06 Thread Otto Moerbeek
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 -   1.44
+++ bcode.c 7 Nov 2012 06:45:52 -
@@ -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;
boolneg;
-   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
-