Mercurial > hg > xemacs-beta
changeset 2013:f2fdfc131770
[xemacs-hg @ 2004-04-14 22:50:52 by james]
Work around GMP string to number limitations.
author | james |
---|---|
date | Wed, 14 Apr 2004 22:50:54 +0000 |
parents | dd25e95fdbe1 |
children | 92f7301e4a23 |
files | src/ChangeLog src/data.c src/lread.c src/number.c |
diffstat | 4 files changed, 81 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog Wed Apr 14 21:50:42 2004 +0000 +++ b/src/ChangeLog Wed Apr 14 22:50:54 2004 +0000 @@ -1,3 +1,10 @@ +2004-04-14 Jerry James <james@xemacs.org> + + * data.c (Fstring_to_number): Work around limitations of GMP + string to number converting functions. + * lread.c (read_atom): Comment fix: the behavior is not random. + * number.c (string_to_bignum): Ditto. + 2004-04-13 Jerry James <james@xemacs.org> * data.c (Fstring_to_number): Skip leading + sign to avoid
--- a/src/data.c Wed Apr 14 21:50:42 2004 +0000 +++ b/src/data.c Wed Apr 14 22:50:54 2004 +0000 @@ -1271,7 +1271,10 @@ #ifdef HAVE_BIGFLOAT else { - /* GMP bigfloat_set_string returns random values with initial + */ + /* The GMP version of bigfloat_set_string (mpf_set_str) has the + following limitation: if p starts with a '+' sign, it does + nothing; i.e., it leaves its bigfloat argument untouched. + Therefore, move p past any leading '+' signs. */ if (*p == '+') p++; bigfloat_set_prec (scratch_bigfloat, bigfloat_get_default_prec ()); @@ -1284,24 +1287,81 @@ #ifdef HAVE_RATIO if (qxestrchr (p, '/') != NULL) { - /* GMP ratio_set_string returns random values with initial + sign */ + /* The GMP version of ratio_set_string (mpq_set_str) has the following + limitations: + - If p starts with a '+' sign, it does nothing; i.e., it leaves its + ratio argument untouched. + - If p has a '+' sign after the '/' (e.g., 300/+400), it sets the + numerator from the string, but *leaves the denominator unchanged*. + - If p has trailing nonnumeric characters, it sets the numerator from + the string, but leaves the denominator unchanged. + - If p has more than one '/', (e.g., 1/2/3), then it sets the + numerator from the string, but leaves the denominator unchanged. + + Therefore, move p past any leading '+' signs, temporarily drop a null + after the numeric characters we are trying to convert, and then put + the nulled character back afterward. I am not going to fix problem + #2; just don't write ratios that look like that. */ + Ibyte *end, save; + if (*p == '+') p++; + + for (end = p; + (*end >= '0' && *end <= '9') || + (b > 10 && *end >= 'a' && *end <= 'a' + b - 11) || + (b > 10 && *end >= 'A' && *end <= 'A' + b - 11); + end++); + if (*end == '/') + for (end++; + (*end >= '0' && *end <= '9') || + (b > 10 && *end >= 'a' && *end <= 'a' + b - 11) || + (b > 10 && *end >= 'A' && *end <= 'A' + b - 11); + end++); + + save = *end; + *end = '\0'; ratio_set_string (scratch_ratio, (const char *) p, b); + *end = save; + ratio_canonicalize (scratch_ratio); return make_ratio_rt (scratch_ratio); } #endif /* HAVE_RATIO */ #ifdef HAVE_BIGNUM - /* GMP bignum_set_string returns random values when the string starts with a - plus sign */ - if (*p == '+') - p++; - /* GMP bignum_set_string returns random values when fed an empty string */ - if (*p == '\0') - return make_int (0); - bignum_set_string (scratch_bignum, (const char *) p, b); - return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + { + /* The GMP version of bignum_set_string (mpz_set_str) has the following + limitations: + - If p starts with a '+' sign, it does nothing; i.e., it leaves its + bignum argument untouched. + - If p is the empty string, it does nothing. + - If p has trailing nonnumeric characters, it does nothing. + + Therefore, move p past any leading '+' signs, temporarily drop a null + after the numeric characters we are trying to convert, special case the + empty string, and then put the nulled character back afterward. */ + Ibyte *end, save; + Lisp_Object retval; + + if (*p == '+') + p++; + for (end = p; + (*end >= '0' && *end <= '9') || + (b > 10 && *end >= 'a' && *end <= 'a' + b - 11) || + (b > 10 && *end >= 'A' && *end <= 'A' + b - 11); + end++); + save = *end; + *end = '\0'; + if (*p == '\0') + retval = make_int (0); + else + { + bignum_set_string (scratch_bignum, (const char *) p, b); + retval = Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } + *end = save; + return retval; + } #else if (b == 10) {
--- a/src/lread.c Wed Apr 14 21:50:42 2004 +0000 +++ b/src/lread.c Wed Apr 14 22:50:54 2004 +0000 @@ -1851,7 +1851,7 @@ #ifdef HAVE_RATIO if (isratio_string (read_ptr)) { - /* GMP ratio_set_string returns random values with initial + sign */ + /* GMP ratio_set_string has no effect with initial + sign */ if (*read_ptr == '+') read_ptr++; ratio_set_string (scratch_ratio, read_ptr, 0);
--- a/src/number.c Wed Apr 14 21:50:42 2004 +0000 +++ b/src/number.c Wed Apr 14 22:50:54 2004 +0000 @@ -85,10 +85,10 @@ string_to_bignum (const Ibyte *str, Bytecount len, int base) { Lisp_Object b = make_bignum (0L); - /* GMP bignum_set_string returns random values with initial + sign */ + /* GMP bignum_set_string has no effect with initial + sign */ if (*str == '+') str++; - /* GMP bignum_set_string returns random values when fed an empty string */ + /* GMP bignum_set_string has no effect when fed an empty string */ if (*str == '\0') return make_int (0); return (bignum_set_string (XBIGNUM_DATA (b), (const char *) str, base) < 0)