/* -*-c-*-
*
- * $Id: mpx.c,v 1.13 2002/10/19 17:56:50 mdw Exp $
+ * $Id: mpx.c,v 1.16 2003/05/16 09:09:24 mdw Exp $
*
* Low-level multiprecision arithmetic
*
/*----- Revision history --------------------------------------------------*
*
* $Log: mpx.c,v $
+ * Revision 1.16 2003/05/16 09:09:24 mdw
+ * Fix @mp_lsl2c@. Turns out to be surprisingly tricky.
+ *
+ * Revision 1.15 2002/10/20 01:12:31 mdw
+ * Two's complement I/O fixes.
+ *
+ * Revision 1.14 2002/10/19 18:55:08 mdw
+ * Fix overflows in shift primitives.
+ *
* Revision 1.13 2002/10/19 17:56:50 mdw
* Fix bit operations. Test them (a bit) better.
*
bits -= 8;
}
b = U8(~b + c);
- c = !b;
+ c = c && !b;
*p++ = b;
}
while (p < q) {
b = U8(~b + c);
- c = !b;
+ c = c && !b;
*p++ = b;
b = 0;
}
return;
while (p < q) {
n = U8(~(*p++) + c);
- c = !n;
+ c = c && !n;
w |= n << bits;
bits += 8;
if (bits >= MPW_BITS) {
bits -= 8;
}
b = U8(~b + c);
- c = !b;
+ c = c && !b;
*--q = b;
}
while (q > p) {
b = ~b + c;
- c = !(b & 0xff);
+ c = c && !(b & 0xff);
*--q = b;
b = 0;
}
return;
while (q > p) {
n = U8(~(*--q) + c);
- c = !n;
+ c = c && !n;
w |= n << bits;
bits += 8;
if (bits >= MPW_BITS) {
/* --- Handle a shift by a multiple of the word size --- */
if (nb == 0) {
- MPX_COPY(dv + nw, dvl, av, avl);
- memset(dv, 0, MPWS(nw));
+ if (nw >= dvl - dv)
+ MPX_ZERO(dv, dvl);
+ else {
+ MPX_COPY(dv + nw, dvl, av, avl);
+ memset(dv, 0, MPWS(nw));
+ }
}
/* --- And finally the difficult case --- *
done:;
}
+/* --- @mpx_lslc@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift left operation on an integer, only
+ * it fills in the bits with ones instead of zeroes.
+ */
+
+void mpx_lslc(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
+{
+ size_t nw;
+ unsigned nb;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0)
+ MPX_COPY(dv, dvl, av, avl);
+
+ /* --- Single bit shifting --- */
+
+ else if (n == 1) {
+ mpw w = 1;
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((t << 1) | w);
+ w = t >> (MPW_BITS - 1);
+ }
+ if (dv >= dvl)
+ goto done;
+ *dv++ = MPW(w);
+ MPX_ZERO(dv, dvl);
+ goto done;
+ }
+
+ /* --- Break out word and bit shifts for more sophisticated work --- */
+
+ nw = n / MPW_BITS;
+ nb = n % MPW_BITS;
+
+ /* --- Handle a shift by a multiple of the word size --- */
+
+ if (nb == 0) {
+ if (nw >= dvl - dv)
+ MPX_ONE(dv, dvl);
+ else {
+ MPX_COPY(dv + nw, dvl, av, avl);
+ MPX_ONE(dv, dv + nw);
+ }
+ }
+
+ /* --- And finally the difficult case --- *
+ *
+ * This is a little convoluted, because I have to start from the end and
+ * work backwards to avoid overwriting the source, if they're both the same
+ * block of memory.
+ */
+
+ else {
+ mpw w;
+ size_t nr = MPW_BITS - nb;
+ size_t dvn = dvl - dv;
+ size_t avn = avl - av;
+
+ if (dvn <= nw) {
+ MPX_ONE(dv, dvl);
+ goto done;
+ }
+
+ if (dvn > avn + nw) {
+ size_t off = avn + nw + 1;
+ MPX_ZERO(dv + off, dvl);
+ dvl = dv + off;
+ w = 0;
+ } else {
+ avl = av + dvn - nw;
+ w = *--avl << nb;
+ }
+
+ while (avl > av) {
+ mpw t = *--avl;
+ *--dvl = (t >> nr) | w;
+ w = t << nb;
+ }
+
+ *--dvl = (MPW_MAX >> nr) | w;
+ MPX_ONE(dv, dvl);
+ }
+
+done:;
+}
+
/* --- @mpx_lsr@ --- *
*
* Arguments: @mpw *dv, *dvl@ = destination vector base and limit
/* --- Handle a shift by a multiple of the word size --- */
- if (nb == 0)
- MPX_COPY(dv, dvl, av + nw, avl);
+ if (nb == 0) {
+ if (nw >= avl - av)
+ MPX_ZERO(dv, dvl);
+ else
+ MPX_COPY(dv, dvl, av + nw, avl);
+ }
/* --- And finally the difficult case --- */
size_t nr = MPW_BITS - nb;
av += nw;
- w = *av++;
+ w = av < avl ? *av++ : 0;
while (av < avl) {
mpw t;
if (dv >= dvl)
return (ok);
}
+static int lslc(dstr *v)
+{
+ mpw *a, *al;
+ int n = *(int *)v[1].buf;
+ mpw *c, *cl;
+ mpw *d, *dl;
+ int ok = 1;
+
+ LOAD(a, al, &v[0]);
+ LOAD(c, cl, &v[2]);
+ ALLOC(d, dl, al - a + (n + MPW_BITS - 1) / MPW_BITS);
+
+ mpx_lslc(d, dl, a, al, n);
+ if (!mpx_ueq(d, dl, c, cl)) {
+ fprintf(stderr, "\n*** lslc(%i) failed\n", n);
+ dumpmp(" a", a, al);
+ dumpmp("expected", c, cl);
+ dumpmp(" result", d, dl);
+ ok = 0;
+ }
+
+ free(a); free(c); free(d);
+ return (ok);
+}
+
static int lsr(dstr *v)
{
mpw *a, *al;
{ "2cl", twocl, { &type_hex, &type_hex, } },
{ "2cb", twocb, { &type_hex, &type_hex, } },
{ "lsl", lsl, { &type_hex, &type_int, &type_hex, 0 } },
+ { "lslc", lslc, { &type_hex, &type_int, &type_hex, 0 } },
{ "lsr", lsr, { &type_hex, &type_int, &type_hex, 0 } },
{ "uadd", uadd, { &type_hex, &type_hex, &type_hex, 0 } },
{ "usub", usub, { &type_hex, &type_hex, &type_hex, 0 } },