diff --git a/core/math/math-tests.factor b/core/math/math-tests.factor index 9dcba0e6d1..fd3ad94c95 100644 --- a/core/math/math-tests.factor +++ b/core/math/math-tests.factor @@ -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 diff --git a/vm/bignum.cpp b/vm/bignum.cpp index b4c1aa86c2..5b78e19d98 100644 --- a/vm/bignum.cpp +++ b/vm/bignum.cpp @@ -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(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(bn), false_object); + + if (!bignum_fits_fixnum_p(bn)) { + general_error(ERROR_OUT_OF_FIXNUM_RANGE, tag(bn), false_object); } fixnum fix = bignum_to_fixnum(bn); FACTOR_ASSERT(fix <= fixnum_max && fix >= fixnum_min); diff --git a/vm/bignum.hpp b/vm/bignum.hpp index 4c939fde02..fb6f063dbb 100644 --- a/vm/bignum.hpp +++ b/vm/bignum.hpp @@ -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); diff --git a/vm/math.cpp b/vm/math.cpp index 149009790f..e46dc80b62 100644 --- a/vm/math.cpp +++ b/vm/math.cpp @@ -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(bn); -} - void factor_vm::primitive_bignum_to_fixnum() { ctx->replace(tag_fixnum(bignum_to_fixnum(untag(ctx->peek())))); }