X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/1a05a8ef4cf287194d595bc6749f6ed6585d3352..75263f25a1ce8e7b38ad4bd61a9a893723ec1db3:/mpx.c diff --git a/mpx.c b/mpx.c index 13b6fa0..b88bd49 100644 --- a/mpx.c +++ b/mpx.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: mpx.c,v 1.10 2000/10/08 12:06:12 mdw Exp $ + * $Id: mpx.c,v 1.13 2002/10/19 17:56:50 mdw Exp $ * * Low-level multiprecision arithmetic * @@ -30,6 +30,15 @@ /*----- Revision history --------------------------------------------------* * * $Log: mpx.c,v $ + * Revision 1.13 2002/10/19 17:56:50 mdw + * Fix bit operations. Test them (a bit) better. + * + * Revision 1.12 2002/10/06 22:52:50 mdw + * Pile of changes for supporting two's complement properly. + * + * Revision 1.11 2001/04/03 19:36:05 mdw + * Add some simple bitwise operations so that Perl can use them. + * * Revision 1.10 2000/10/08 12:06:12 mdw * Provide @mpx_ueq@ for rapidly testing equality of two integers. * @@ -75,6 +84,7 @@ #include "mptypes.h" #include "mpx.h" +#include "bitops.h" /*----- Loading and storing -----------------------------------------------*/ @@ -230,6 +240,186 @@ void mpx_loadb(mpw *v, mpw *vl, const void *pp, size_t sz) MPX_ZERO(v, vl); } +/* --- @mpx_storel2cn@ --- * + * + * Arguments: @const mpw *v, *vl@ = base and limit of source vector + * @void *pp@ = pointer to octet array + * @size_t sz@ = size of octet array + * + * Returns: --- + * + * Use: Stores a negative MP in an octet array, least significant + * octet first, as two's complement. High-end octets are + * silently discarded if there isn't enough space for them. + * This obviously makes the output bad. + */ + +void mpx_storel2cn(const mpw *v, const mpw *vl, void *pp, size_t sz) +{ + unsigned c = 1; + unsigned b = 0; + mpw n, w = 0; + octet *p = pp, *q = p + sz; + unsigned bits = 0; + + while (p < q) { + if (bits < 8) { + if (v >= vl) { + b = w; + break; + } + n = *v++; + b = w | n << bits; + w = n >> (8 - bits); + bits += MPW_BITS - 8; + } else { + b = w; + w >>= 8; + bits -= 8; + } + b = U8(~b + c); + c = !b; + *p++ = b; + } + while (p < q) { + b = U8(~b + c); + c = !b; + *p++ = b; + b = 0; + } +} + +/* --- @mpx_loadl2cn@ --- * + * + * Arguments: @mpw *v, *vl@ = base and limit of destination vector + * @const void *pp@ = pointer to octet array + * @size_t sz@ = size of octet array + * + * Returns: --- + * + * Use: Loads a negative MP in an octet array, least significant + * octet first, as two's complement. High-end octets are + * ignored if there isn't enough space for them. This probably + * means you made the wrong choice coming here. + */ + +void mpx_loadl2cn(mpw *v, mpw *vl, const void *pp, size_t sz) +{ + unsigned n; + unsigned c = 1; + mpw w = 0; + const octet *p = pp, *q = p + sz; + unsigned bits = 0; + + if (v >= vl) + return; + while (p < q) { + n = U8(~(*p++) + c); + c = !n; + w |= n << bits; + bits += 8; + if (bits >= MPW_BITS) { + *v++ = MPW(w); + w = n >> (MPW_BITS - bits + 8); + bits -= MPW_BITS; + if (v >= vl) + return; + } + } + *v++ = w; + MPX_ZERO(v, vl); +} + +/* --- @mpx_storeb2cn@ --- * + * + * Arguments: @const mpw *v, *vl@ = base and limit of source vector + * @void *pp@ = pointer to octet array + * @size_t sz@ = size of octet array + * + * Returns: --- + * + * Use: Stores a negative MP in an octet array, most significant + * octet first, as two's complement. High-end octets are + * silently discarded if there isn't enough space for them, + * which probably isn't what you meant. + */ + +void mpx_storeb2cn(const mpw *v, const mpw *vl, void *pp, size_t sz) +{ + mpw n, w = 0; + unsigned b = 0; + unsigned c = 1; + octet *p = pp, *q = p + sz; + unsigned bits = 0; + + while (q > p) { + if (bits < 8) { + if (v >= vl) { + b = w; + break; + } + n = *v++; + b = w | n << bits; + w = n >> (8 - bits); + bits += MPW_BITS - 8; + } else { + b = w; + w >>= 8; + bits -= 8; + } + b = U8(~b + c); + c = !b; + *--q = b; + } + while (q > p) { + b = ~b + c; + c = !(b & 0xff); + *--q = b; + b = 0; + } +} + +/* --- @mpx_loadb2cn@ --- * + * + * Arguments: @mpw *v, *vl@ = base and limit of destination vector + * @const void *pp@ = pointer to octet array + * @size_t sz@ = size of octet array + * + * Returns: --- + * + * Use: Loads a negative MP in an octet array, most significant octet + * first as two's complement. High-end octets are ignored if + * there isn't enough space for them. This probably means you + * chose this function wrongly. + */ + +void mpx_loadb2cn(mpw *v, mpw *vl, const void *pp, size_t sz) +{ + unsigned n; + unsigned c = 1; + mpw w = 0; + const octet *p = pp, *q = p + sz; + unsigned bits = 0; + + if (v >= vl) + return; + while (q > p) { + n = U8(~(*--q) + c); + c = !n; + w |= n << bits; + bits += 8; + if (bits >= MPW_BITS) { + *v++ = MPW(w); + w = n >> (MPW_BITS - bits + 8); + bits -= MPW_BITS; + if (v >= vl) + return; + } + } + *v++ = w; + MPX_ZERO(v, vl); +} + /*----- Logical shifting --------------------------------------------------*/ /* --- @mpx_lsl@ --- * @@ -400,6 +590,48 @@ void mpx_lsr(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n) done:; } +/*----- Bitwise operations ------------------------------------------------*/ + +/* --- @mpx_bitop@ --- * + * + * Arguments: @mpw *dv, *dvl@ = destination vector + * @const mpw *av, *avl@ = first source vector + * @const mpw *bv, *bvl@ = second source vector + * + * Returns: --- + * + * Use; Provides the dyadic boolean functions. + */ + +#define MPX_BITBINOP(string) \ + \ +void mpx_bit##string(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, \ + const mpw *bv, const mpw *bvl) \ +{ \ + MPX_SHRINK(av, avl); \ + MPX_SHRINK(bv, bvl); \ + \ + while (dv < dvl) { \ + mpw a, b; \ + a = (av < avl) ? *av++ : 0; \ + b = (bv < bvl) ? *bv++ : 0; \ + *dv++ = B##string(a, b); \ + } \ +} + +MPX_DOBIN(MPX_BITBINOP) + +void mpx_not(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl) +{ + MPX_SHRINK(av, avl); + + while (dv < dvl) { + mpw a; + a = (av < avl) ? *av++ : 0; + *dv++ = ~a; + } +} + /*----- Unsigned arithmetic -----------------------------------------------*/ /* --- @mpx_2c@ --- * @@ -1083,6 +1315,84 @@ static int loadstore(dstr *v) return (ok); } +static int twocl(dstr *v) +{ + dstr d = DSTR_INIT; + mpw *m, *ml; + size_t sz; + int ok = 1; + + sz = v[0].len; if (v[1].len > sz) sz = v[1].len; + dstr_ensure(&d, sz); + + sz = MPW_RQ(sz); + m = xmalloc(MPWS(sz)); + ml = m + sz; + + mpx_loadl(m, ml, v[0].buf, v[0].len); + mpx_storel2cn(m, ml, d.buf, v[1].len); + if (memcmp(d.buf, v[1].buf, v[1].len)) { + dumpbits("\n*** storel2cn failed", d.buf, v[1].len); + ok = 0; + } + + mpx_loadl2cn(m, ml, v[1].buf, v[1].len); + mpx_storel(m, ml, d.buf, v[0].len); + if (memcmp(d.buf, v[0].buf, v[0].len)) { + dumpbits("\n*** loadl2cn failed", d.buf, v[0].len); + ok = 0; + } + + if (!ok) { + dumpbits("pos", v[0].buf, v[0].len); + dumpbits("neg", v[1].buf, v[1].len); + } + + free(m); + dstr_destroy(&d); + + return (ok); +} + +static int twocb(dstr *v) +{ + dstr d = DSTR_INIT; + mpw *m, *ml; + size_t sz; + int ok = 1; + + sz = v[0].len; if (v[1].len > sz) sz = v[1].len; + dstr_ensure(&d, sz); + + sz = MPW_RQ(sz); + m = xmalloc(MPWS(sz)); + ml = m + sz; + + mpx_loadb(m, ml, v[0].buf, v[0].len); + mpx_storeb2cn(m, ml, d.buf, v[1].len); + if (memcmp(d.buf, v[1].buf, v[1].len)) { + dumpbits("\n*** storeb2cn failed", d.buf, v[1].len); + ok = 0; + } + + mpx_loadb2cn(m, ml, v[1].buf, v[1].len); + mpx_storeb(m, ml, d.buf, v[0].len); + if (memcmp(d.buf, v[0].buf, v[0].len)) { + dumpbits("\n*** loadb2cn failed", d.buf, v[0].len); + ok = 0; + } + + if (!ok) { + dumpbits("pos", v[0].buf, v[0].len); + dumpbits("neg", v[1].buf, v[1].len); + } + + free(m); + dstr_destroy(&d); + + return (ok); +} + static int lsl(dstr *v) { mpw *a, *al; @@ -1273,6 +1583,8 @@ static int udiv(dstr *v) static test_chunk defs[] = { { "load-store", loadstore, { &type_hex, 0 } }, + { "2cl", twocl, { &type_hex, &type_hex, } }, + { "2cb", twocb, { &type_hex, &type_hex, } }, { "lsl", lsl, { &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 } },