mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-07-16 17:37:34 +02:00
updating more bitwise corner cases (issue #408)
This commit is contained in:
parent
383c6cba62
commit
5fb3217ada
2 changed files with 47 additions and 16 deletions
|
@ -16,6 +16,13 @@
|
||||||
#define sexp_bignum_normalize(x) x
|
#define sexp_bignum_normalize(x) x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The twos complement form of a negative bignum has a -1 sign */
|
||||||
|
/* and bits adjusted as usual, extending just the high word with */
|
||||||
|
/* leading ones. Bitwise operations are then performed as usual. */
|
||||||
|
/* If the result has a leading extended one from a twos complement */
|
||||||
|
/* number, the complement is reversed and sign remains negative. */
|
||||||
|
/* Otherwise, the result is positive, the sign is set to 1 and there's */
|
||||||
|
/* no need to undo the complement. */
|
||||||
static void sexp_set_twos_complement (sexp a) {
|
static void sexp_set_twos_complement (sexp a) {
|
||||||
int i, len=sexp_bignum_length(a), carry = 1;
|
int i, len=sexp_bignum_length(a), carry = 1;
|
||||||
sexp_uint_t* data = sexp_bignum_data(a), n;
|
sexp_uint_t* data = sexp_bignum_data(a), n;
|
||||||
|
@ -34,7 +41,6 @@ static sexp sexp_twos_complement (sexp ctx, sexp x) {
|
||||||
if (sexp_bignump(x) && sexp_bignum_sign(x) < 0) {
|
if (sexp_bignump(x) && sexp_bignum_sign(x) < 0) {
|
||||||
sexp_gc_preserve1(ctx, res);
|
sexp_gc_preserve1(ctx, res);
|
||||||
res = sexp_copy_bignum(ctx, NULL, x, 0);
|
res = sexp_copy_bignum(ctx, NULL, x, 0);
|
||||||
sexp_bignum_sign(res) = 1;
|
|
||||||
sexp_set_twos_complement(res);
|
sexp_set_twos_complement(res);
|
||||||
sexp_gc_release1(ctx);
|
sexp_gc_release1(ctx);
|
||||||
return res;
|
return res;
|
||||||
|
@ -52,13 +58,17 @@ static sexp sexp_fixnum_to_twos_complement (sexp ctx, sexp x, int len) {
|
||||||
sexp_bignum_data(res)[i] = (sexp_uint_t)((sexp_sint_t)-1);
|
sexp_bignum_data(res)[i] = (sexp_uint_t)((sexp_sint_t)-1);
|
||||||
sexp_bignum_data(res)[0] = ~(-(sexp_unbox_fixnum(x)));
|
sexp_bignum_data(res)[0] = ~(-(sexp_unbox_fixnum(x)));
|
||||||
res = sexp_bignum_fxadd(ctx, res, 1);
|
res = sexp_bignum_fxadd(ctx, res, 1);
|
||||||
|
if (sexp_bignum_length(res) == len + 1 && sexp_bignum_data(res)[len] == 1)
|
||||||
|
sexp_bignum_data(res)[len] = -1;
|
||||||
|
if (sexp_unbox_fixnum(x) < 0)
|
||||||
|
sexp_bignum_sign(res) = -1;
|
||||||
sexp_gc_release1(ctx);
|
sexp_gc_release1(ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
#if SEXP_USE_BIGNUMS
|
#if SEXP_USE_BIGNUMS
|
||||||
sexp_sint_t len, i;
|
sexp_sint_t len, lenx, leny, i;
|
||||||
#endif
|
#endif
|
||||||
sexp_gc_var3(res, x2, y2);
|
sexp_gc_var3(res, x2, y2);
|
||||||
if (sexp_fixnump(x) && sexp_fixnump(y)) {
|
if (sexp_fixnump(x) && sexp_fixnump(y)) {
|
||||||
|
@ -75,13 +85,24 @@ sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
if (sexp_fixnump(y2)) {
|
if (sexp_fixnump(y2)) {
|
||||||
res = sexp_make_fixnum(sexp_unbox_fixnum(y2) & sexp_bignum_data(x2)[0]);
|
res = sexp_make_fixnum(sexp_unbox_fixnum(y2) & sexp_bignum_data(x2)[0]);
|
||||||
} else if (sexp_bignump(y2)) {
|
} else if (sexp_bignump(y2)) {
|
||||||
if (sexp_bignum_length(x2) < sexp_bignum_length(y2))
|
lenx = sexp_bignum_length(x2);
|
||||||
|
leny = sexp_bignum_length(y2);
|
||||||
|
if (leny < lenx)
|
||||||
res = sexp_copy_bignum(ctx, NULL, x2, 0);
|
res = sexp_copy_bignum(ctx, NULL, x2, 0);
|
||||||
else
|
else
|
||||||
res = sexp_copy_bignum(ctx, NULL, y2, 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(x2)[i] & sexp_bignum_data(y2)[i];
|
= (i<lenx ? sexp_bignum_data(x2)[i] : sexp_bignum_sign(x2) < 0 ? -1 : 0) &
|
||||||
|
(i<leny ? sexp_bignum_data(y2)[i] : sexp_bignum_sign(y2) < 0 ? -1 : 0);
|
||||||
|
if ((sexp_bignum_sign(x2) < 0 || sexp_bignum_sign(y2) < 0) && ((sexp_sint_t)(sexp_bignum_data(res)[len-1])) < 0) {
|
||||||
|
sexp_set_twos_complement(res);
|
||||||
|
if (sexp_bignum_sign(res) > 0) {
|
||||||
|
sexp_negate_exact(res);
|
||||||
|
}
|
||||||
|
} else if (sexp_bignum_sign(res) < 0) {
|
||||||
|
sexp_negate_exact(res);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y2);
|
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y2);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +116,7 @@ sexp sexp_bit_and (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
|
|
||||||
sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
#if SEXP_USE_BIGNUMS
|
#if SEXP_USE_BIGNUMS
|
||||||
sexp_sint_t len, i;
|
sexp_sint_t len, tmplen, i;
|
||||||
#endif
|
#endif
|
||||||
sexp_gc_var2(res, tmp);
|
sexp_gc_var2(res, tmp);
|
||||||
if (sexp_fixnump(x)) {
|
if (sexp_fixnump(x)) {
|
||||||
|
@ -120,21 +141,23 @@ sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
} else if (sexp_bignump(y) || sexp_fixnump(y)) {
|
} else if (sexp_bignump(y) || sexp_fixnump(y)) {
|
||||||
if (sexp_fixnump(y) || sexp_bignum_length(x) >= sexp_bignum_length(y)) {
|
if (sexp_fixnump(y) || sexp_bignum_length(x) >= sexp_bignum_length(y)) {
|
||||||
res = sexp_copy_bignum(ctx, NULL, x, 0);
|
res = sexp_copy_bignum(ctx, NULL, x, 0);
|
||||||
tmp = sexp_fixnump(y) ? sexp_fixnum_to_twos_complement(ctx, y, sexp_bignum_length(x)) : sexp_twos_complement(ctx, y);
|
len = sexp_bignum_length(res);
|
||||||
len = sexp_bignum_length(tmp);
|
tmp = sexp_fixnump(y) ? sexp_fixnum_to_twos_complement(ctx, y, len) : sexp_twos_complement(ctx, y);
|
||||||
} else {
|
} else {
|
||||||
res = sexp_copy_bignum(ctx, NULL, y, 0);
|
res = sexp_copy_bignum(ctx, NULL, y, 0);
|
||||||
|
len = sexp_bignum_length(res);
|
||||||
tmp = sexp_twos_complement(ctx, x);
|
tmp = sexp_twos_complement(ctx, x);
|
||||||
len = sexp_bignum_length(tmp);
|
|
||||||
}
|
}
|
||||||
if (sexp_bignum_sign(res) < 0)
|
if (sexp_bignum_sign(res) < 0)
|
||||||
sexp_set_twos_complement(res);
|
sexp_set_twos_complement(res);
|
||||||
|
tmplen = sexp_bignum_length(tmp);
|
||||||
for (i=0; i<len; i++)
|
for (i=0; i<len; i++)
|
||||||
sexp_bignum_data(res)[i] |= sexp_bignum_data(tmp)[i];
|
sexp_bignum_data(res)[i] |= (i<tmplen ? sexp_bignum_data(tmp)[i] : sexp_bignum_sign(tmp) < 0 ? -1 : 0);
|
||||||
if ((sexp_bignum_sign(x) < 0) ^ (sexp_fixnump(y) || sexp_bignum_sign(y) < 0))
|
if ((sexp_bignum_sign(res) < 0 || sexp_bignum_sign(tmp) < 0) && ((sexp_sint_t)(sexp_bignum_data(res)[len-1])) < 0) {
|
||||||
sexp_set_twos_complement(res);
|
sexp_set_twos_complement(res);
|
||||||
if (sexp_fixnump(y) || sexp_bignum_sign(y) < 0) {
|
if (sexp_bignum_sign(res) > 0) {
|
||||||
sexp_negate_exact(res);
|
sexp_negate_exact(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y);
|
res = sexp_type_exception(ctx, self, SEXP_FIXNUM, y);
|
||||||
|
@ -149,7 +172,7 @@ sexp sexp_bit_ior (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
|
|
||||||
sexp sexp_bit_xor (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
sexp sexp_bit_xor (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
#if SEXP_USE_BIGNUMS
|
#if SEXP_USE_BIGNUMS
|
||||||
sexp_sint_t len, i;
|
sexp_sint_t len, tmplen, i;
|
||||||
#endif
|
#endif
|
||||||
sexp_gc_var2(res, tmp);
|
sexp_gc_var2(res, tmp);
|
||||||
if (sexp_fixnump(x)) {
|
if (sexp_fixnump(x)) {
|
||||||
|
@ -183,9 +206,9 @@ sexp sexp_bit_xor (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||||
}
|
}
|
||||||
if (sexp_bignum_sign(res) < 0)
|
if (sexp_bignum_sign(res) < 0)
|
||||||
sexp_set_twos_complement(res);
|
sexp_set_twos_complement(res);
|
||||||
|
tmplen = sexp_bignum_length(tmp);
|
||||||
for (i=0; i<len; i++)
|
for (i=0; i<len; i++)
|
||||||
sexp_bignum_data(res)[i]
|
sexp_bignum_data(res)[i] ^= (i<tmplen ? sexp_bignum_data(tmp)[i] : sexp_bignum_sign(tmp) < 0 ? -1 : 0);
|
||||||
= sexp_bignum_data(res)[i] ^ sexp_bignum_data(tmp)[i];
|
|
||||||
if ((sexp_bignum_sign(x) < 0) ^ (sexp_fixnump(y) || sexp_bignum_sign(y) < 0))
|
if ((sexp_bignum_sign(x) < 0) ^ (sexp_fixnump(y) || sexp_bignum_sign(y) < 0))
|
||||||
sexp_set_twos_complement(res);
|
sexp_set_twos_complement(res);
|
||||||
if (sexp_fixnump(y) || sexp_bignum_sign(y) < 0) {
|
if (sexp_fixnump(y) || sexp_bignum_sign(y) < 0) {
|
||||||
|
@ -401,4 +424,3 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
||||||
sexp_define_foreign(ctx, env, "bit-set?", 2, sexp_bit_set_p);
|
sexp_define_foreign(ctx, env, "bit-set?", 2, sexp_bit_set_p);
|
||||||
return SEXP_VOID;
|
return SEXP_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
(test -2600468497 (bitwise-ior 1694076839 -4290775858))
|
(test -2600468497 (bitwise-ior 1694076839 -4290775858))
|
||||||
(test -184549633 (bitwise-ior -193073517 1689392892))
|
(test -184549633 (bitwise-ior -193073517 1689392892))
|
||||||
(test -167776621 (bitwise-ior -193073517 1689392892000000000000))
|
(test -167776621 (bitwise-ior -193073517 1689392892000000000000))
|
||||||
|
(test -18446744073709551616
|
||||||
|
(bitwise-ior -18446744073709551616
|
||||||
|
340282366920938463463374607431768211456))
|
||||||
|
(test 340282366920938463481821351505477763072
|
||||||
|
(bitwise-ior 18446744073709551616
|
||||||
|
340282366920938463463374607431768211456))
|
||||||
(test -7090566332214939648
|
(test -7090566332214939648
|
||||||
(bitwise-ior -193073517000000000000 1689392892000000000000))
|
(bitwise-ior -193073517000000000000 1689392892000000000000))
|
||||||
(test -351599414102633810746018680881203758247936
|
(test -351599414102633810746018680881203758247936
|
||||||
|
@ -45,6 +51,9 @@
|
||||||
-1689392892000000000000193073517000000000000))
|
-1689392892000000000000193073517000000000000))
|
||||||
(test 3769478 (bitwise-and 1694076839 -4290775858))
|
(test 3769478 (bitwise-and 1694076839 -4290775858))
|
||||||
(test 1680869008 (bitwise-and -193073517 1689392892))
|
(test 1680869008 (bitwise-and -193073517 1689392892))
|
||||||
|
(test 340282366920938463463374607431768211456
|
||||||
|
(bitwise-and 340282366920938463463374607431768211456
|
||||||
|
(bitwise-not 18446744073709551616)))
|
||||||
|
|
||||||
(test 1 (arithmetic-shift 1 0))
|
(test 1 (arithmetic-shift 1 0))
|
||||||
(test 2 (arithmetic-shift 1 1))
|
(test 2 (arithmetic-shift 1 1))
|
||||||
|
|
Loading…
Add table
Reference in a new issue