From 57207b88184f005616de1af4af5e9e9632a4503a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 23 Mar 2014 01:52:36 +0200 Subject: [PATCH] objint_mpz: Quick&dirty implementation of bitwise operations. Made solely to unbreak int-long.py test which in turn uncovered thinko with implementation of inplace ops. On mpz level, bitwise ops implemented only for same-sign numbers, and are not efficient (unconditional calling of mpn_cmp() is apparently superfluous). --- py/mpz.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ py/mpz.h | 3 ++ py/objint_mpz.c | 20 +++++--- 3 files changed, 148 insertions(+), 7 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 16198730af..79d200d930 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -173,6 +173,69 @@ STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz return idig + 1 - oidig; } +/* computes i = j & k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) { + mpz_dig_t *oidig = idig; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig & *kdig; + } + + for (; jlen > 0; --jlen, ++idig) { + *idig = 0; + } + + return idig - oidig; +} + +/* computes i = j | k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC uint mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) { + mpz_dig_t *oidig = idig; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig | *kdig; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + *idig = *jdig; + } + + return idig - oidig; +} + +/* computes i = j ^ k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC uint mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) { + mpz_dig_t *oidig = idig; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig ^ *kdig; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + *idig = *jdig; + } + + return idig - oidig; +} + /* computes i = i * d1 + d2 returns number of digits in i assumes enough memory in i; assumes normalised i; assumes dmul != 0 @@ -805,6 +868,75 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { } } +/* computes dest = lhs & rhs + can have dest, lhs, rhs the same +*/ +void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + if (lhs->neg == rhs->neg) { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + mpz_need_dig(dest, lhs->len); + // TODO + assert(0); +// dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } + + dest->neg = lhs->neg; +} + +/* computes dest = lhs | rhs + can have dest, lhs, rhs the same +*/ +void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + if (lhs->neg == rhs->neg) { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + mpz_need_dig(dest, lhs->len); + // TODO + assert(0); +// dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } + + dest->neg = lhs->neg; +} + +/* computes dest = lhs ^ rhs + can have dest, lhs, rhs the same +*/ +void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + if (lhs->neg == rhs->neg) { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + mpz_need_dig(dest, lhs->len); + // TODO + assert(0); +// dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } + + dest->neg = 0; +} + /* computes dest = lhs * rhs can have dest, lhs, rhs the same */ diff --git a/py/mpz.h b/py/mpz.h index afd46cfdea..7778893229 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -59,6 +59,9 @@ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2); mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 05e300ddc9..25d8af70ee 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -78,7 +78,7 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return mp_obj_new_float(flhs / frhs); #endif - } else if (op <= RT_BINARY_OP_POWER) { + } else if (op <= RT_BINARY_OP_INPLACE_POWER) { mp_obj_int_t *res = mp_obj_int_new_mpz(); switch (op) { @@ -119,12 +119,18 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { break; } - //case RT_BINARY_OP_AND: - //case RT_BINARY_OP_INPLACE_AND: - //case RT_BINARY_OP_OR: - //case RT_BINARY_OP_INPLACE_OR: - //case RT_BINARY_OP_XOR: - //case RT_BINARY_OP_INPLACE_XOR: + case RT_BINARY_OP_AND: + case RT_BINARY_OP_INPLACE_AND: + mpz_and_inpl(&res->mpz, zlhs, zrhs); + break; + case RT_BINARY_OP_OR: + case RT_BINARY_OP_INPLACE_OR: + mpz_or_inpl(&res->mpz, zlhs, zrhs); + break; + case RT_BINARY_OP_XOR: + case RT_BINARY_OP_INPLACE_XOR: + mpz_xor_inpl(&res->mpz, zlhs, zrhs); + break; case RT_BINARY_OP_LSHIFT: case RT_BINARY_OP_INPLACE_LSHIFT: