Fixing bitwise-and for negative bignums

(necessary for sha2 implementation on 32-bit machines).
This commit is contained in:
Alex Shinn 2014-06-29 11:28:56 +09:00
parent 5a510560ca
commit bb3ac57b6d
2 changed files with 64 additions and 20 deletions

View file

@ -16,40 +16,70 @@
#define sexp_bignum_normalize(x) x #define sexp_bignum_normalize(x) x
#endif #endif
static sexp sexp_twos_complement (sexp ctx, sexp x) {
int i;
sexp_gc_var1(res);
if (sexp_bignump(x) && sexp_bignum_sign(x) < 0) {
sexp_gc_preserve1(ctx, res);
res = sexp_copy_bignum(ctx, NULL, x, 0);
sexp_bignum_sign(res) = 1;
for (i = sexp_bignum_length(res)-1; i >= 0; i--)
sexp_bignum_data(res)[i] = ~sexp_bignum_data(res)[i];
res = sexp_bignum_fxadd(ctx, res, 1);
sexp_gc_release1(ctx);
return res;
}
return x;
}
static sexp sexp_fixnum_to_twos_complement (sexp ctx, sexp x, int len) {
int i;
sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res);
res = sexp_make_bignum(ctx, len);
for (i = len-1; i > 0; i--)
sexp_bignum_data(res)[i] = (sexp_uint_t)((sexp_sint_t)-1);
sexp_bignum_data(res)[0] = ~(-(sexp_unbox_fixnum(x)));
res = sexp_bignum_fxadd(ctx, res, 1);
sexp_gc_release1(ctx);
return res;
}
static sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) { static sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
sexp res;
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS
sexp_sint_t len, i; sexp_sint_t len, i;
#endif #endif
if (sexp_fixnump(x)) { sexp_gc_var3(res, x2, y2);
if (sexp_fixnump(y)) if (sexp_fixnump(x) && sexp_fixnump(y)) {
res = (sexp) ((sexp_uint_t)x & (sexp_uint_t)y); return (sexp) ((sexp_uint_t)x & (sexp_uint_t)y); /* safe to AND tags */
#if SEXP_USE_BIGNUMS
else if (sexp_bignump(y))
res = sexp_bit_and(ctx, self, n, y, x);
#endif
else
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y);
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS
} else if (sexp_fixnump(x) && sexp_bignump(y)) {
return sexp_bit_and(ctx, self, n, y, x);
} else if (sexp_bignump(x)) { } else if (sexp_bignump(x)) {
if (sexp_fixnump(y)) { sexp_gc_preserve3(ctx, res, x2, y2);
res = sexp_make_fixnum(sexp_unbox_fixnum(y) & sexp_bignum_data(x)[0]); x2 = sexp_twos_complement(ctx, x);
} else if (sexp_bignump(y)) { y2 = sexp_twos_complement(ctx, y);
if (sexp_bignum_length(x) < sexp_bignum_length(y)) if (sexp_fixnump(y2) && sexp_negativep(y2))
res = sexp_copy_bignum(ctx, NULL, x, 0); y2 = sexp_fixnum_to_twos_complement(ctx, y2, sexp_bignum_length(x2));
if (sexp_fixnump(y2)) {
res = sexp_make_fixnum(sexp_unbox_fixnum(y2) & sexp_bignum_data(x2)[0]);
} else if (sexp_bignump(y2)) {
if (sexp_bignum_length(x2) < sexp_bignum_length(y2))
res = sexp_copy_bignum(ctx, NULL, x2, 0);
else else
res = sexp_copy_bignum(ctx, NULL, y, 0); res = sexp_copy_bignum(ctx, NULL, y2, 0);
for (i=0, len=sexp_bignum_length(res); i<len; i++) for (i=0, len=sexp_bignum_length(res); i<len; i++)
sexp_bignum_data(res)[i] sexp_bignum_data(res)[i]
= sexp_bignum_data(x)[i] & sexp_bignum_data(y)[i]; = sexp_bignum_data(x2)[i] & sexp_bignum_data(y2)[i];
} else { } else {
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y); res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y2);
} }
sexp_gc_release3(ctx);
return sexp_bignum_normalize(res);
#endif #endif
} else { } else {
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, x); return sexp_type_exception(ctx, self, SEXP_FIXNUM, x);
} }
return sexp_bignum_normalize(res);
} }
static sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) { static sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {

View file

@ -3,6 +3,20 @@
(test-begin "srfi-33") (test-begin "srfi-33")
(test 0 (bitwise-and #b0 #b1))
(test 1 (bitwise-and #b1 #b1))
(test 0 (bitwise-and #b1 #b10))
(test #b10 (bitwise-and #b11 #b10))
(test #b101 (bitwise-and #b101 #b111))
(test #b111 (bitwise-and -1 #b111))
(test #b110 (bitwise-and -2 #b111))
(test 3769478 (bitwise-and -4290775858 1694076839))
(test 1680869008 (bitwise-and -193073517 1689392892))
;; (test -2600468497 (bitwise-ior 1694076839 -4290775858))
;; (test -184549633 (bitwise-ior -193073517 1689392892))
;; (test -2604237975 (bitwise-xor 1694076839 -4290775858))
;; (test -1865418641 (bitwise-xor -193073517 1689392892))
(test 1 (arithmetic-shift 1 0)) (test 1 (arithmetic-shift 1 0))
(test 2 (arithmetic-shift 1 1)) (test 2 (arithmetic-shift 1 1))
(test 4 (arithmetic-shift 1 2)) (test 4 (arithmetic-shift 1 2))