X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/a297c21674d7453888b13597d5c12b1ff5853a90..81578196d5732e443c75768ba9118c581c407cc7:/mpx.c diff --git a/mpx.c b/mpx.c index 6375c3e..f40d7d9 100644 --- a/mpx.c +++ b/mpx.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: mpx.c,v 1.15 2002/10/20 01:12:31 mdw Exp $ + * $Id: mpx.c,v 1.16 2003/05/16 09:09:24 mdw Exp $ * * Low-level multiprecision arithmetic * @@ -30,6 +30,9 @@ /*----- 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. * @@ -525,6 +528,104 @@ void mpx_lsl(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n) 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 @@ -1432,6 +1533,31 @@ static int lsl(dstr *v) 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; @@ -1600,6 +1726,7 @@ static test_chunk defs[] = { { "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 } },