VM: fix bignum>fixnum-strict conversion, previously most-negative-fixnum

>bignum bignum>fixnum-strict didn't work
db4
Björn Lindqvist 2015-06-28 14:49:12 +02:00
parent 95fa3eba19
commit ed702209ce
4 changed files with 24 additions and 16 deletions

View File

@ -1,4 +1,4 @@
USING: kernel math namespaces make tools.test ;
USING: kernel layouts math math.private namespaces make tools.test ;
IN: math.tests
[ ] [ 5 [ ] times ] unit-test
@ -96,3 +96,5 @@ IN: math.tests
{ t } [ 128 2^ sq 256 2^ = ] unit-test
{ t } [ 128 2^ neg sq 256 2^ = ] unit-test
{ t } [ most-negative-fixnum dup >bignum bignum>fixnum-strict = ] unit-test

View File

@ -388,12 +388,28 @@ BIGNUM_TO_FOO(fixnum, fixnum, fixnum, cell)
BIGNUM_TO_FOO(long_long, int64_t, int64_t, uint64_t)
BIGNUM_TO_FOO(ulong_long, uint64_t, int64_t, uint64_t)
bool bignum_fits_fixnum_p(bignum* bn) {
fixnum len = BIGNUM_LENGTH(bn);
if (len == 0)
return true;
if (len > 1)
return false;
bignum_digit_type dig = BIGNUM_START_PTR(bn)[0];
return (BIGNUM_NEGATIVE_P(bn) && dig <= -fixnum_min) ||
(!BIGNUM_NEGATIVE_P(bn) && dig <= fixnum_max);
}
cell bignum_maybe_to_fixnum(bignum* bn) {
if (bignum_fits_fixnum_p(bn))
return tag_fixnum(bignum_to_fixnum(bn));
return tag<bignum>(bn);
}
/* cannot allocate memory */
fixnum factor_vm::bignum_to_fixnum_strict(bignum* bn) {
fixnum len = BIGNUM_LENGTH(bn);
bignum_digit_type *digits = BIGNUM_START_PTR(bn);
if ((len == 1 && digits[0] > fixnum_max) || (len > 1)) {
general_error(ERROR_OUT_OF_FIXNUM_RANGE, tag<bignum>(bn), false_object);
if (!bignum_fits_fixnum_p(bn)) {
general_error(ERROR_OUT_OF_FIXNUM_RANGE, tag<bignum>(bn), false_object);
}
fixnum fix = bignum_to_fixnum(bn);
FACTOR_ASSERT(fix <= fixnum_max && fix >= fixnum_min);

View File

@ -42,6 +42,7 @@ enum bignum_comparison {
bignum_comparison_greater = 1
};
cell bignum_maybe_to_fixnum(bignum* bn);
cell bignum_to_cell(bignum* bn);
fixnum bignum_to_fixnum(bignum* bn);
int64_t bignum_to_long_long(bignum* bn);

View File

@ -2,17 +2,6 @@
namespace factor {
cell bignum_maybe_to_fixnum(bignum* bn) {
if (BIGNUM_ZERO_P(bn))
return tag_fixnum(0);
fixnum len = BIGNUM_LENGTH(bn);
bignum_digit_type *digits = BIGNUM_START_PTR(bn);
if (len == 1 && digits[0] >= fixnum_min && digits[0] <= fixnum_max) {
return tag_fixnum(bignum_to_fixnum(bn));
}
return tag<bignum>(bn);
}
void factor_vm::primitive_bignum_to_fixnum() {
ctx->replace(tag_fixnum(bignum_to_fixnum(untag<bignum>(ctx->peek()))));
}