creachadair / imath

Arbitrary precision integer and rational arithmetic library
Other
129 stars 20 forks source link

Missing Xor, Or & And functions #51

Closed infradig closed 3 years ago

infradig commented 3 years ago

But, pardon the roughshod code, here's my version. As usual, you are free to make use of the code as you see fit & I transfer copyright...

/ Here there be dragons /

static mp_digit s_uor(mp_digit da, mp_digit db, mp_digit *dc, mp_size size_a, mp_size size_b) { mp_size pos; mp_word w = 0;

/ Insure that da is the longer of the two to simplify later code / if (size_b > size_a) { SWAP(mp_digit *, da, db); SWAP(mp_size, size_a, size_b); }

/ Or corresponding digits until the shorter number runs out / for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { w = w + ((mp_word)da | (mp_word)db); *dc = LOWER_HALF(w); w = UPPER_HALF(w); }

for (/ /; pos < size_a; ++pos, ++da, ++dc) { w = w | *da;

*dc = LOWER_HALF(w);
w = UPPER_HALF(w);

}

/ Return carry out / return (mp_digit)w; }

static mp_digit s_uxor(mp_digit da, mp_digit db, mp_digit *dc, mp_size size_a, mp_size size_b) { mp_size pos; mp_word w = 0;

/ Insure that da is the longer of the two to simplify later code / if (size_b > size_a) { SWAP(mp_digit *, da, db); SWAP(mp_size, size_a, size_b); }

/ Xor corresponding digits until the shorter number runs out / for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { w = w + ((mp_word)da ^ (mp_word)db); *dc = LOWER_HALF(w); w = UPPER_HALF(w); }

/ Propagate carries as far as necessary / for (/ /; pos < size_a; ++pos, ++da, ++dc) { w = w ^ *da;

*dc = LOWER_HALF(w);
w = UPPER_HALF(w);

}

/ Return carry out / return (mp_digit)w; }

static mp_digit s_uand(mp_digit da, mp_digit db, mp_digit *dc, mp_size size_a, mp_size size_b) { mp_size pos; mp_word w = 0;

/ Insure that da is the longer of the two to simplify later code / if (size_b > size_a) { SWAP(mp_digit *, da, db); SWAP(mp_size, size_a, size_b); }

/ And corresponding digits until the shorter number runs out / for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { w = w + ((mp_word)da & (mp_word)db); *dc = LOWER_HALF(w); w = UPPER_HALF(w); }

/ Propagate carries as far as necessary / for (/ /; pos < size_a; ++pos, ++da, ++dc) { w = w & *da;

*dc = LOWER_HALF(w);
w = UPPER_HALF(w);

}

/ Return carry out / return (mp_digit)w; }

mp_result mp_int_or(mp_int a, mp_int b, mp_int c) { assert(a != NULL && b != NULL && c != NULL);

if (MP_SIGN(a) != MP_SIGN(b)) return MP_BADARG;

mp_size ua = MP_USED(a); mp_size ub = MP_USED(b); mp_size max = MAX(ua, ub); if (!s_pad(c, max)) return MP_MEMORY;

mp_digit carry = s_uor(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); mp_size uc = max;

if (carry) { if (!s_pad(c, max + 1)) return MP_MEMORY;

c->digits[max] = carry;
++uc;

}

c->used = uc; c->sign = a->sign; return MP_OK; }

mp_result mp_int_xor(mp_int a, mp_int b, mp_int c) { assert(a != NULL && b != NULL && c != NULL);

if (MP_SIGN(a) != MP_SIGN(b)) return MP_BADARG;

mp_size ua = MP_USED(a); mp_size ub = MP_USED(b); mp_size max = MAX(ua, ub); if (!s_pad(c, max)) return MP_MEMORY;

mp_digit carry = s_uxor(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); mp_size uc = max;

if (carry) { if (!s_pad(c, max + 1)) return MP_MEMORY;

c->digits[max] = carry;
++uc;

}

/ Drop those leading zeros / while (c->digits[--max] == 0) uc--;

c->used = uc; c->sign = a->sign; return MP_OK; }

mp_result mp_int_and(mp_int a, mp_int b, mp_int c) { assert(a != NULL && b != NULL && c != NULL);

if (MP_SIGN(a) != MP_SIGN(b)) return MP_BADARG;

mp_size ua = MP_USED(a); mp_size ub = MP_USED(b); mp_size min = MIN(ua, ub);

s_uand(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);

c->used = min; c->sign = a->sign; return MP_OK; }

creachadair commented 3 years ago

Thank you for the proposal. I am not convinced that bitwise operations are generally-enough needed, that I want to add them into the core library. It seems easy enough to implement them separately that their absence from the core arithmetic won’t prevent someone from doing that.

If I were going to add this functionality, the tests would also need to be updated to cover the new API entry points. Probably also I would want to see it built separately from the main lib, as with the rational extensions. I could maybe be convinced to merge a PR built along those lines.

infradig commented 3 years ago

No problems. Unfortunately it needs to be in imath.c as it uses private information. I'll stick with maintaining my local modification for now.