From 40bae281a56c9e305852905dcbd29125de388b25 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 1 Oct 2012 17:35:10 -0700 Subject: * arith.c (bignum_from_long): New function. * arith.h (bignum_from_long): Declared. * lib.c (int_str): Streamlined. Only use mp_read_radix in the case when wcstol fails, because now we have bignum_from_long to handle all values of long. Ensure that the bignum is normalized, in case it falls in the fixnum range (does not happen on our usual platforms). --- ChangeLog | 11 +++++++++++ arith.c | 11 +++++++++++ arith.h | 1 + lib.c | 17 +++++++++++------ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8015cdd2..389134a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2012-10-01 Kaz Kylheku + + * arith.c (bignum_from_long): New function. + + * arith.h (bignum_from_long): Declared. + + * lib.c (int_str): Streamlined. Only use mp_read_radix in the case when + wcstol fails, because now we have bignum_from_long to handle all values + of long. Ensure that the bignum is normalized, in case it falls in the + fixnum range (does not happen on our usual platforms). + 2012-09-25 Kaz Kylheku * eval.c: Allow the test form of a for loop to be omitted, diff --git a/arith.c b/arith.c index 8e245e71..b1ae1677 100644 --- a/arith.c +++ b/arith.c @@ -68,6 +68,17 @@ val bignum(cnum cn) return n; } +val bignum_from_long(long l) +{ +#if SIZEOF_LONG <= SIZEOF_PTR + return bignum(l); +#else + val n = make_bignum(); + mp_set_int(mp(n), l); + return n; +#endif +} + #if HAVE_DOUBLE_INTPTR_T static val bignum_dbl_ipt(double_intptr_t di) diff --git a/arith.h b/arith.h index 52aad603..8a97dd87 100644 --- a/arith.h +++ b/arith.h @@ -26,6 +26,7 @@ val make_bignum(void); val bignum(cnum cn); +val bignum_from_long(long l); int highest_bit(int_ptr_t n); val normalize(val bignum); val in_int_ptr_range(val bignum); diff --git a/lib.c b/lib.c index 89a38496..fcbcae15 100644 --- a/lib.c +++ b/lib.c @@ -2104,11 +2104,11 @@ val int_str(val str, val base) /* TODO: detect if we have wcstoll */ long value = wcstol(wcs, &ptr, b ? b : 10); + if (value == 0 && ptr == wcs) return nil; - if (((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE) || - (value < NUM_MIN || value > NUM_MAX)) - { + + if ((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE) { val bignum = make_bignum(); unsigned char *ucs = utf8_dup_to_uc(wcs); mp_err err = mp_read_radix(mp(bignum), ucs, b); @@ -2118,10 +2118,15 @@ val int_str(val str, val base) if (err != MP_OKAY) return nil; - return bignum; - } + /* If wcstol overflowed, but the range of long is smaller than + that of fixnums, that means that the value might not + actually be a bignum, and so we must normalize. + We do not need this on our usual target platforms, where NUM_MAX is + never larger than LONG_MAX. */ + return (LONG_MAX < NUM_MAX) ? normalize(bignum) : bignum; + } - return num(value); + return bignum_from_long(value); } val flo_str(val str) -- cgit v1.2.3