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).
This commit is contained in:
Paul Sokolovsky 2014-03-23 01:52:36 +02:00
parent fd232c3ef7
commit 57207b8818
3 changed files with 148 additions and 7 deletions

132
py/mpz.c
View File

@ -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; 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 /* computes i = i * d1 + d2
returns number of digits in i returns number of digits in i
assumes enough memory in i; assumes normalised i; assumes dmul != 0 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 /* computes dest = lhs * rhs
can have dest, lhs, rhs the same can have dest, lhs, rhs the same
*/ */

View File

@ -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_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_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_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_gcd(const mpz_t *z1, const mpz_t *z2);
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2); mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2);

View File

@ -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); return mp_obj_new_float(flhs / frhs);
#endif #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(); mp_obj_int_t *res = mp_obj_int_new_mpz();
switch (op) { 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; break;
} }
//case RT_BINARY_OP_AND: case RT_BINARY_OP_AND:
//case RT_BINARY_OP_INPLACE_AND: case RT_BINARY_OP_INPLACE_AND:
//case RT_BINARY_OP_OR: mpz_and_inpl(&res->mpz, zlhs, zrhs);
//case RT_BINARY_OP_INPLACE_OR: break;
//case RT_BINARY_OP_XOR: case RT_BINARY_OP_OR:
//case RT_BINARY_OP_INPLACE_XOR: 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_LSHIFT:
case RT_BINARY_OP_INPLACE_LSHIFT: case RT_BINARY_OP_INPLACE_LSHIFT: