diff options
author | Alex Shinn <ashinn@users.noreply.github.com> | 2012-12-04 19:48:14 +0900 |
---|---|---|
committer | Alex Shinn <ashinn@users.noreply.github.com> | 2012-12-04 19:48:14 +0900 |
commit | e9963b4a5733737ee00757b7c19510f19976f4da (patch) | |
tree | 26c4ceeb28110d020487308c3241d3073b8e300c | |
parent | 5909732e82d56240b79110471b5aaca6bb51ce9a (diff) |
Initial hugenums implementation (incomplete).hugenums
-rw-r--r-- | bignum.c | 322 | ||||
-rw-r--r-- | eval.c | 57 | ||||
-rw-r--r-- | include/chibi/bignum.h | 5 | ||||
-rw-r--r-- | include/chibi/eval.h | 3 | ||||
-rw-r--r-- | include/chibi/features.h | 24 | ||||
-rwxr-xr-x | include/chibi/sexp.h | 50 | ||||
-rw-r--r-- | opcodes.c | 2 | ||||
-rw-r--r-- | sexp.c | 160 |
8 files changed, 518 insertions, 105 deletions
@@ -233,13 +233,13 @@ sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init, res = sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in); } else { if (c!='.') sexp_push_char(ctx, c, in); /* push the e back */ - res = sexp_read_float_tail(ctx, in, sexp_bignum_to_double(res), (sign==-1)); + res = sexp_read_float_tail(ctx, in, sexp_bignum_to_double(res), (sign==-1), 0); } #if SEXP_USE_RATIOS } else if (c=='/') { res = sexp_bignum_normalize(res); res = sexp_make_ratio(ctx, res, SEXP_ONE); - sexp_ratio_denominator(res) = sexp_read_number(ctx, in, 10); + sexp_ratio_denominator(res) = sexp_read_number(ctx, in, 10, 1); res = sexp_ratio_normalize(ctx, res, in); #endif #if SEXP_USE_COMPLEX @@ -839,6 +839,109 @@ sexp sexp_complex_atan (sexp ctx, sexp z) { #endif #endif +#if SEXP_USE_HUGENUMS + +/* Conway's chained arrows */ + +/* Here a, b, c are integers, and X, Y are arbitrary subchains. */ + +/* 1. a = a */ +/* 2. a->b = a^b */ +/* 3. X->1->... = X */ +/* 4. X->(a+1)->(b+1) = X->(X->a->(b+1))->b */ + +/* Alternate forms */ + +/* a->b->c = hyper(a, c+2, b) in hyper notation */ +/* = a^^...^^b in Knuth's arrow notation */ +/* c '^'s */ + +/* Ackermann(a, b) = (2->(a+3)->(b-2)) - 3 for b > 2*/ + +/* Special cases */ + +/* 2->2->X = 4 (will always expand to a power tower of 2 2s) */ +/* X->2->2 = X->(X) (chain X with it's value concatenated to it) */ +/* a->b->2 = a^^b (a tetrated to b) */ +/* a->2->3 = a->a->2 (a tetrated to itself) */ +/* a->3->3 = a->(a->a->2)->2 = a^^(a^^a) */ +/* a->b->c->d = huge for a, b, c, d >= 2, a or b >= 3 */ + +sexp sexp_make_hugenum (sexp ctx, sexp_uint_t len) { + sexp_uint_t size = sexp_sizeof(hugenum) + len*sizeof(sexp); + sexp res = sexp_alloc_tagged(ctx, size, SEXP_HUGENUM); + sexp_hugenum_length(res) = len; + return res; +} + +sexp sexp_copy_hugenum (sexp ctx, sexp a) { + sexp_uint_t i, len = sexp_hugenum_length(a); + sexp_uint_t size = sexp_sizeof(hugenum) + len*sizeof(sexp); + sexp res = sexp_alloc_tagged(ctx, size, SEXP_HUGENUM); + sexp_hugenum_length(res) = len; + for (i=0; i<len; i++) sexp_hugenum_data(res)[i] = sexp_hugenum_data(a)[i]; + return res; +} + +sexp sexp_hugenum2 (sexp ctx, sexp base, sexp exponent) { + sexp res = sexp_make_hugenum(ctx, 2); + sexp_hugenum_data(res)[0] = base; + sexp_hugenum_data(res)[1] = exponent; + return res; +} + +int sexp_hugenum_sign (sexp a) { + sexp first = sexp_hugenum_data(a)[0]; + if (sexp_fixnump(first)) + return sexp_unbox_fixnum(first); + if (sexp_bignump(first)) + return sexp_bignum_sign(first); + return 0; /* shouldn't happen */ +} + +int sexp_compare_hugenum_magnitude (sexp ctx, sexp a, sexp b, int sign) { + sexp *av, *bv; + int i, diff; + sexp_gc_var2(loga, logb); + if ((diff = sexp_hugenum_length(a) - sexp_hugenum_length(b)) != 0) + return diff * sign; + if (sexp_hugenum_length(a) == 2) { + sexp_gc_preserve2(ctx, loga, logb); + loga = sexp_log(ctx, a); + logb = sexp_log(ctx, b); + diff = sexp_unbox_fixnum(sexp_compare(ctx, loga, logb)); + sexp_gc_release2(ctx); + return diff; + } + av = sexp_hugenum_data(a); + bv = sexp_hugenum_data(b); + for (i=sexp_hugenum_length(a); i>=0; i--) + if ((diff = sexp_unbox_fixnum(sexp_compare(ctx, av[i], bv[i]))) != 0) + return diff * sign; + return 0; +} + +int sexp_compare_hugenum (sexp ctx, sexp a, sexp b) { + int sign; + if ((sign = sexp_hugenum_sign(a)) != sexp_hugenum_sign(b)) + return sign; + return sexp_compare_hugenum_magnitude(ctx, a, b, sign); +} + +sexp sexp_max_hugenum_magnitude (sexp ctx, sexp a, sexp b) { + if (sexp_compare_hugenum_magnitude(ctx, a, b, 1) < 0) + return b; + return a; +} + +sexp sexp_max_hugenum (sexp ctx, sexp a, sexp b) { + if (sexp_compare_hugenum(ctx, a, b) < 0) + return b; + return a; +} + +#endif + /****************** generic arithmetic ************************/ enum sexp_number_types { @@ -852,6 +955,9 @@ enum sexp_number_types { #if SEXP_USE_COMPLEX SEXP_NUM_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_HUG, +#endif }; enum sexp_number_combs { @@ -865,6 +971,9 @@ enum sexp_number_combs { #if SEXP_USE_COMPLEX SEXP_NUM_NOT_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_NOT_HUG, +#endif SEXP_NUM_FIX_NOT, SEXP_NUM_FIX_FIX, SEXP_NUM_FIX_FLO, @@ -875,6 +984,9 @@ enum sexp_number_combs { #if SEXP_USE_COMPLEX SEXP_NUM_FIX_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_FIX_HUG, +#endif SEXP_NUM_FLO_NOT, SEXP_NUM_FLO_FIX, SEXP_NUM_FLO_FLO, @@ -885,6 +997,9 @@ enum sexp_number_combs { #if SEXP_USE_COMPLEX SEXP_NUM_FLO_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_FLO_HUG, +#endif SEXP_NUM_BIG_NOT, SEXP_NUM_BIG_FIX, SEXP_NUM_BIG_FLO, @@ -895,6 +1010,9 @@ enum sexp_number_combs { #if SEXP_USE_COMPLEX SEXP_NUM_BIG_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_BIG_HUG, +#endif #if SEXP_USE_RATIOS SEXP_NUM_RAT_NOT, SEXP_NUM_RAT_FIX, @@ -904,6 +1022,9 @@ enum sexp_number_combs { #if SEXP_USE_COMPLEX SEXP_NUM_RAT_CPX, #endif +#if SEXP_USE_HUGENUMS + SEXP_NUM_RAT_HUG, +#endif #endif #if SEXP_USE_COMPLEX SEXP_NUM_CPX_NOT, @@ -914,11 +1035,28 @@ enum sexp_number_combs { SEXP_NUM_CPX_RAT, #endif SEXP_NUM_CPX_CPX, +#if SEXP_USE_HUGENUMS + SEXP_NUM_CPX_HUG, +#endif +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_HUG_NOT, + SEXP_NUM_HUG_FIX, + SEXP_NUM_HUG_FLO, + SEXP_NUM_HUG_BIG, + SEXP_NUM_HUG_RAT, +#if SEXP_USE_HUGENUMS + SEXP_NUM_HUG_CPX, +#endif + SEXP_NUM_HUG_HUG, #endif }; static int sexp_number_types[] = -#if SEXP_USE_RATIOS && SEXP_USE_COMPLEX +#if SEXP_USE_HUGENUMS && SEXP_USE_COMPLEX + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 0}; +#else +#if SEXP_USE_RATIOS && (SEXP_USE_COMPLEX || SEXP_USE_HUGENUMS) {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 0, 0}; #else #if SEXP_USE_RATIOS || SEXP_USE_COMPLEX @@ -927,8 +1065,9 @@ static int sexp_number_types[] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0}; #endif #endif +#endif -#define SEXP_NUM_NUMBER_TYPES (4 + SEXP_USE_RATIOS + SEXP_USE_COMPLEX) +#define SEXP_NUM_NUMBER_TYPES (4 + SEXP_USE_RATIOS + SEXP_USE_COMPLEX + SEXP_USE_HUGENUMS) static int sexp_number_type (sexp a) { return sexp_pointerp(a) ? @@ -940,6 +1079,16 @@ static int sexp_number_type (sexp a) { : sexp_fixnump(a); } +#if SEXP_USE_RATIOS +#define sexp_rat_case(x) case x: +#endif +#if SEXP_USE_COMPLEX +#define sexp_cpx_case(x) case x: +#endif +#if SEXP_USE_HUGENUMS +#define sexp_hug_case(x) case x: +#endif + sexp sexp_add (sexp ctx, sexp a, sexp b) { sexp_sint_t sum; int at=sexp_number_type(a), bt=sexp_number_type(b), t; @@ -950,12 +1099,9 @@ sexp sexp_add (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_NOT_RAT: -#endif -#if SEXP_USE_COMPLEX - case SEXP_NUM_NOT_CPX: -#endif + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_FIX: @@ -993,9 +1139,7 @@ sexp sexp_add (sexp ctx, sexp a, sexp b) { break; #endif #if SEXP_USE_COMPLEX -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_CPX: -#endif + sexp_rat_case(SEXP_NUM_RAT_CPX) case SEXP_NUM_FLO_CPX: case SEXP_NUM_FIX_CPX: case SEXP_NUM_BIG_CPX: @@ -1005,6 +1149,23 @@ sexp sexp_add (sexp ctx, sexp a, sexp b) { r = sexp_complex_add(ctx, a, b); break; #endif +#if SEXP_USE_HUGENUMS + case SEXP_NUM_FLO_HUG: + r = sexp_infp(a) ? a : b; + break; + case SEXP_NUM_RAT_HUG: + case SEXP_NUM_FIX_HUG: + case SEXP_NUM_BIG_HUG: + r = b; + break; + case SEXP_NUM_CPX_HUG: + b = tmp = sexp_make_complex(ctx, b, SEXP_ZERO); + r = sexp_complex_add(ctx, a, b); + break; + case SEXP_NUM_HUG_HUG: + r = sexp_max_hugenum_magnitude(ctx, a, b); + break; +#endif } sexp_gc_release1(ctx); return r; @@ -1021,21 +1182,14 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_NOT_RAT: -#endif -#if SEXP_USE_COMPLEX - case SEXP_NUM_NOT_CPX: -#endif + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_NOT: case SEXP_NUM_FLO_NOT: case SEXP_NUM_BIG_NOT: -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_NOT: -#endif -#if SEXP_USE_COMPLEX - case SEXP_NUM_CPX_NOT: -#endif + sexp_rat_case(SEXP_NUM_RAT_NOT) + sexp_cpx_case(SEXP_NUM_CPX_NOT) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, b); break; case SEXP_NUM_FIX_FIX: @@ -1133,6 +1287,40 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) { } break; #endif +#if SEXP_USE_HUGENUMS + case SEXP_NUM_HUG_FLO: + case SEXP_NUM_HUG_RAT: + case SEXP_NUM_HUG_FIX: + case SEXP_NUM_HUG_BIG: + r = tmp1 = sexp_sub(ctx, b, a); + if (sexp_hugenump(r)) r = sexp_copy_hugenum(ctx, r); + sexp_negate(r); + break; + case SEXP_NUM_FLO_HUG: + if (sexp_infp(a)) { + r = a; + } else { + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_HUG: + case SEXP_NUM_FIX_HUG: + case SEXP_NUM_BIG_HUG: + r = sexp_copy_hugenum(ctx, b); + sexp_negate(r); + } + break; + case SEXP_NUM_CPX_HUG: + b = tmp1 = sexp_make_complex(ctx, b, SEXP_ZERO); + r = sexp_complex_sub(ctx, a, b); + break; + case SEXP_NUM_HUG_HUG: + if (sexp_compare_hugenum_magnitude(ctx, a, b, 1) > 0) { + r = a; + } else { + r = tmp1 = sexp_copy_hugenum(ctx, b); + sexp_negate(r); + } + break; +#endif } sexp_gc_release2(ctx); return r; @@ -1148,9 +1336,9 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_NOT_RAT: -#endif + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_FIX: @@ -1189,9 +1377,7 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) { break; #endif #if SEXP_USE_COMPLEX -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_CPX: -#endif + sexp_rat_case(SEXP_NUM_RAT_CPX) case SEXP_NUM_FLO_CPX: case SEXP_NUM_FIX_CPX: case SEXP_NUM_BIG_CPX: @@ -1201,6 +1387,33 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) { r = sexp_complex_mul(ctx, a, b); break; #endif +#if SEXP_USE_HUGENUMS + case SEXP_NUM_FLO_HUG: + if (sexp_infp(a)) { + r = sexp_mul(ctx, a, sexp_make_fixnum(sexp_hugenum_sign(b))); + } else { + r = sexp_copy_hugenum(ctx, b); + if (sexp_flonum_value(a) < 0) { + sexp_negate(r); + } + } + break; + case SEXP_NUM_RAT_HUG: + case SEXP_NUM_FIX_HUG: + case SEXP_NUM_BIG_HUG: + r = sexp_copy_hugenum(ctx, b); + if (sexp_negativep(a) < 0) { + sexp_negate(r); + } + break; + case SEXP_NUM_CPX_HUG: + b = tmp = sexp_make_complex(ctx, b, SEXP_ZERO); + r = sexp_complex_add(ctx, a, b); + break; + case SEXP_NUM_HUG_HUG: + r = sexp_max_hugenum_magnitude(ctx, a, b); + break; +#endif } sexp_gc_release1(ctx); return r; @@ -1217,15 +1430,13 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_NOT_RAT: -#endif + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_NOT: case SEXP_NUM_FLO_NOT: case SEXP_NUM_BIG_NOT: -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_NOT: -#endif + sexp_rat_case(SEXP_NUM_RAT_NOT) r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, b); break; case SEXP_NUM_FIX_FIX: @@ -1349,15 +1560,16 @@ sexp sexp_quotient (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); break; case SEXP_NUM_FIX_NOT: case SEXP_NUM_FLO_NOT: case SEXP_NUM_BIG_NOT: r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); break; case SEXP_NUM_FLO_FIX: case SEXP_NUM_FLO_FLO: case SEXP_NUM_FLO_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_FLO_RAT: -#endif + sexp_rat_case(SEXP_NUM_FLO_RAT) if (sexp_flonum_value(a) != trunc(sexp_flonum_value(a))) { r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); } else { @@ -1372,16 +1584,12 @@ sexp sexp_quotient (sexp ctx, sexp a, sexp b) { #if SEXP_USE_COMPLEX case SEXP_NUM_FLO_CPX: case SEXP_NUM_CPX_FIX: case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_BIG: case SEXP_NUM_CPX_CPX: -#if SEXP_USE_RATIOS - case SEXP_NUM_CPX_RAT: -#endif + sexp_rat_case(SEXP_NUM_CPX_RAT) #endif r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); break; case SEXP_NUM_FIX_FLO: case SEXP_NUM_BIG_FLO: -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_FLO: -#endif + sexp_rat_case(SEXP_NUM_RAT_FLO) if (sexp_flonum_value(b) != trunc(sexp_flonum_value(b))) { r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); } else { @@ -1423,15 +1631,16 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); break; case SEXP_NUM_FIX_NOT: case SEXP_NUM_FLO_NOT: case SEXP_NUM_BIG_NOT: r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); break; case SEXP_NUM_FLO_FIX: case SEXP_NUM_FLO_FLO: case SEXP_NUM_FLO_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_FLO_RAT: -#endif + sexp_rat_case(SEXP_NUM_FLO_RAT) if (sexp_flonum_value(a) != trunc(sexp_flonum_value(a))) { r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); } else { @@ -1446,16 +1655,12 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) { #if SEXP_USE_COMPLEX case SEXP_NUM_FLO_CPX: case SEXP_NUM_CPX_FIX: case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_BIG: case SEXP_NUM_CPX_CPX: -#if SEXP_USE_RATIOS - case SEXP_NUM_CPX_RAT: -#endif + sexp_rat_case(SEXP_NUM_CPX_RAT) #endif r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); break; case SEXP_NUM_FIX_FLO: case SEXP_NUM_BIG_FLO: -#if SEXP_USE_RATIOS - case SEXP_NUM_RAT_FLO: -#endif + sexp_rat_case(SEXP_NUM_RAT_FLO) if (sexp_flonum_value(b) != trunc(sexp_flonum_value(b))) { r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); } else { @@ -1502,12 +1707,13 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: + sexp_rat_case(SEXP_NUM_NOT_RAT) + sexp_cpx_case(SEXP_NUM_NOT_CPX) + sexp_hug_case(SEXP_NUM_NOT_HUG) #if SEXP_USE_COMPLEX case SEXP_NUM_CPX_CPX: case SEXP_NUM_CPX_FIX: case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_BIG: -#if SEXP_USE_RATIOS - case SEXP_NUM_CPX_RAT: -#endif + sexp_rat_case(SEXP_NUM_CPX_RAT) #endif r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; @@ -1308,7 +1308,6 @@ sexp sexp_register_optimization (sexp ctx, sexp self, sexp_sint_t n, sexp f, sex } define_math_op(sexp_exp, exp, sexp_complex_exp) -define_math_op(sexp_log, log, sexp_complex_log) define_math_op(sexp_sin, sin, sexp_complex_sin) define_math_op(sexp_cos, cos, sexp_complex_cos) define_math_op(sexp_tan, tan, sexp_complex_tan) @@ -1381,6 +1380,34 @@ sexp sexp_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) { return res; } +sexp sexp_log_op (sexp ctx, sexp self, sexp_sint_t n, sexp z) { + double d; + sexp_gc_var1(tmp); + if (sexp_flonump(z)) + d = sexp_flonum_value(z); + else if (sexp_fixnump(z)) + d = (double)sexp_unbox_fixnum(z); + maybe_convert_ratio(z) + maybe_convert_bignum(z) + maybe_convert_complex(z, sexp_complex_log) +#if SEXP_USE_HUGENUMS + else if (sexp_hugenump(z)) { + if (sexp_hugenum_length(z) == 2) { + sexp_gc_preserve1(ctx, tmp); + tmp = sexp_log(ctx, sexp_hugenum_data(z)[0]); + tmp = sexp_mul(ctx, tmp, sexp_hugenum_data(z)[1]); + sexp_gc_release1(ctx); + return tmp; + } else { + return z; + } + } +#endif + else + return sexp_type_exception(ctx, self, SEXP_NUMBER, z); + return sexp_make_flonum(ctx, log(d)); +} + #endif /* SEXP_USE_MATH */ #if SEXP_USE_RATIOS || !SEXP_USE_FLONUMS @@ -1403,11 +1430,27 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) { return sexp_generic_expt(ctx, x, sexp_unbox_fixnum(e)); #else long double f, x1, e1; - sexp res; + sexp_gc_var1(res); #if SEXP_USE_COMPLEX if (sexp_complexp(x) || sexp_complexp(e)) return sexp_complex_expt(ctx, x, e); #endif + sexp_gc_preserve1(ctx, res); +#if SEXP_USE_HUGENUMS + if (sexp_hugenump(x)) { + if (sexp_hugenum_length(x) == 2 && (!sexp_hugenump(e) || sexp_hugenum_length(e) <= 2)) { + res = sexp_make_hugenum(ctx, 2); + sexp_hugenum_data(res)[0] = sexp_hugenum_data(x)[0]; + sexp_hugenum_data(res)[1] = sexp_mul(ctx, sexp_hugenum_data(x)[1], e); + } else if (sexp_hugenump(e)) { + res = sexp_max_hugenum(ctx, x, e); + } else { + res = x; + } + } else if (sexp_hugenump(e)) { + res = e; + } else +#endif #if SEXP_USE_BIGNUMS if (sexp_bignump(e)) { /* bignum exponent needs special handling */ if ((x == SEXP_ZERO) || (x == SEXP_NEG_ONE)) @@ -1416,6 +1459,10 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) { res = SEXP_ONE; /* 1.0 */ else if (sexp_flonump(x)) res = sexp_make_flonum(ctx, pow(sexp_flonum_value(x), sexp_bignum_to_double(e))); +#if SEXP_USE_HUGENUMS + else if (sexp_fixnump(x) || sexp_bignump(x)) + res = sexp_hugenum2(ctx, x, e); +#endif else res = sexp_make_flonum(ctx, pow(10.0, 1e100)); /* +inf.0 */ } else if (sexp_bignump(x)) { @@ -1429,14 +1476,17 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) { #if SEXP_USE_RATIOS else if (sexp_ratiop(x)) { if (sexp_fixnump(e)) { + sexp_gc_release1(ctx); return sexp_generic_expt(ctx, x, sexp_unbox_fixnum(e)); } else { x1 = sexp_ratio_to_double(x); } } #endif - else + else { + sexp_gc_release1(ctx); return sexp_type_exception(ctx, self, SEXP_FIXNUM, x); + } if (sexp_fixnump(e)) e1 = sexp_unbox_fixnum(e); else if (sexp_flonump(e)) @@ -1461,6 +1511,7 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) { #if SEXP_USE_BIGNUMS } #endif + sexp_gc_release1(ctx); return res; #endif /* !SEXP_USE_FLONUMS */ } diff --git a/include/chibi/bignum.h b/include/chibi/bignum.h index d23262ee..8666f0aa 100644 --- a/include/chibi/bignum.h +++ b/include/chibi/bignum.h @@ -65,6 +65,11 @@ SEXP_API sexp sexp_complex_asin (sexp ctx, sexp z); SEXP_API sexp sexp_complex_acos (sexp ctx, sexp z); SEXP_API sexp sexp_complex_atan (sexp ctx, sexp z); #endif +#if SEXP_USE_HUGENUMS +SEXP_API sexp sexp_make_hugenum (sexp ctx, sexp_uint_t len); +SEXP_API sexp sexp_hugenum2 (sexp ctx, sexp base, sexp exponent); +SEXP_API sexp sexp_max_hugenum (sexp ctx, sexp a, sexp b); +#endif #endif /* ! SEXP_BIGNUM_H */ diff --git a/include/chibi/eval.h b/include/chibi/eval.h index 9c0c6da1..34aed782 100644 --- a/include/chibi/eval.h +++ b/include/chibi/eval.h @@ -148,7 +148,8 @@ SEXP_API sexp sexp_print_vm_profile (sexp ctx, sexp self, sexp_sint_t n); #if SEXP_USE_MATH SEXP_API sexp sexp_exp(sexp ctx, sexp self, sexp_sint_t n, sexp z); -SEXP_API sexp sexp_log(sexp ctx, sexp self, sexp_sint_t n, sexp z); +SEXP_API sexp sexp_log_op(sexp ctx, sexp self, sexp_sint_t n, sexp z); +#define sexp_log(ctx, z) sexp_log_op(ctx, NULL, 1, z) SEXP_API sexp sexp_sin(sexp ctx, sexp self, sexp_sint_t n, sexp z); SEXP_API sexp sexp_cos(sexp ctx, sexp self, sexp_sint_t n, sexp z); SEXP_API sexp sexp_tan(sexp ctx, sexp self, sexp_sint_t n, sexp z); diff --git a/include/chibi/features.h b/include/chibi/features.h index 1021fb62..c1ed7887 100644 --- a/include/chibi/features.h +++ b/include/chibi/features.h @@ -146,6 +146,9 @@ /* uncomment this if you don't want imaginary number support */ /* #define SEXP_USE_COMPLEX 0 */ +/* uncomment this if you don't want inexact huge number support */ +/* #define SEXP_USE_HUGENUMS 0 */ + /* uncomment this if you don't want 1## style approximate digits */ /* #define SEXP_USE_PLACEHOLDER_DIGITS 0 */ @@ -428,6 +431,23 @@ #define SEXP_USE_COMPLEX SEXP_USE_FLONUMS #endif +#ifndef SEXP_USE_HUGENUMS +#define SEXP_USE_HUGENUMS SEXP_USE_RATIOS +#endif + +/* hugenums imply ratios and complex */ +#if SEXP_USE_HUGENUMS +#undef SEXP_USE_RATIOS +#define SEXP_USE_RATIOS 1 +#undef SEXP_USE_COMPLEX +#define SEXP_USE_COMPLEX 1 +#endif + +#ifndef SEXP_MAX_BIGNUM_LENGTH +#define SEXP_MAX_BIGNUM_LENGTH (128*1024*1024) /* 128MB */ +#endif + +/* either of ratios or complex imply bignums and flonums */ #if (SEXP_USE_RATIOS || SEXP_USE_COMPLEX) #undef SEXP_USE_BIGNUMS #define SEXP_USE_BIGNUMS 1 @@ -462,6 +482,10 @@ #ifndef SEXP_USE_MATH #define SEXP_USE_MATH SEXP_USE_FLONUMS && ! SEXP_USE_NO_FEATURES #endif +#if SEXP_USE_HUGENUMS +#undef SEXP_USE_MATH +#define SEXP_USE_MATH 1 +#endif #ifndef SEXP_USE_ESCAPE_NEWLINE #define SEXP_USE_ESCAPE_NEWLINE ! SEXP_USE_NO_FEATURES diff --git a/include/chibi/sexp.h b/include/chibi/sexp.h index 60e93a24..18f408a9 100755 --- a/include/chibi/sexp.h +++ b/include/chibi/sexp.h @@ -132,6 +132,9 @@ enum sexp_types { #if SEXP_USE_COMPLEX SEXP_COMPLEX, #endif +#if SEXP_USE_HUGENUMS + SEXP_HUGENUM, +#endif SEXP_IPORT, SEXP_OPORT, SEXP_FILENO, @@ -351,6 +354,10 @@ struct sexp_struct { sexp_uint_t data[]; } bignum; struct { + sexp_uint_t length; + sexp data[]; + } hugenum; + struct { sexp numerator, denominator; } ratio; struct { @@ -648,6 +655,11 @@ sexp sexp_make_flonum(sexp ctx, double f); #else #define sexp_complexp(x) 0 #endif +#if SEXP_USE_HUGENUMS +#define sexp_hugenump(x) (sexp_check_tag(x, SEXP_HUGENUM)) +#else +#define sexp_hugenump(x) 0 +#endif #define sexp_cpointerp(x) (sexp_check_tag(x, SEXP_CPOINTER)) #define sexp_exceptionp(x) (sexp_check_tag(x, SEXP_EXCEPTION)) #define sexp_procedurep(x) (sexp_check_tag(x, SEXP_PROCEDURE)) @@ -732,7 +744,11 @@ sexp sexp_make_flonum(sexp ctx, double f); #if SEXP_USE_FLONUMS #define sexp_fp_integerp(x) (sexp_flonum_value(x) == trunc(sexp_flonum_value(x))) +#if SEXP_USE_HUGENUMS +#define _or_integer_flonump(x) || (sexp_flonump(x) && sexp_fp_integerp(x)) || sexp_hugenump(x) +#else #define _or_integer_flonump(x) || (sexp_flonump(x) && sexp_fp_integerp(x)) +#endif #else #define _or_integer_flonump(x) #endif @@ -758,7 +774,11 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #if SEXP_USE_FLONUMS #define sexp_fixnum_to_flonum(ctx, x) (sexp_make_flonum(ctx, sexp_unbox_fixnum(x))) #if SEXP_USE_RATIOS +#if SEXP_USE_HUGENUMS +#define sexp_realp(x) (sexp_exact_integerp(x) || sexp_flonump(x) || sexp_ratiop(x) || sexp_hugenump(x)) +#else #define sexp_realp(x) (sexp_exact_integerp(x) || sexp_flonump(x) || sexp_ratiop(x)) +#endif #else #define sexp_realp(x) (sexp_exact_integerp(x) || sexp_flonump(x)) #endif @@ -773,11 +793,18 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #define sexp_numberp(x) (sexp_realp(x)) #endif -#define sexp_exact_negativep(x) (sexp_fixnump(x) ? (sexp_unbox_fixnum(x) < 0) \ - : (SEXP_USE_BIGNUMS && sexp_bignump(x)) \ - && (sexp_bignum_sign(x) < 0)) -#define sexp_negativep(x) (sexp_exact_negativep(x) || \ - (sexp_flonump(x) && sexp_flonum_value(x) < 0)) +#define sexp_exact_integer_negativep(x) \ + (sexp_fixnump(x) ? (sexp_unbox_fixnum(x) < 0) \ + : (sexp_bignump(x) && (sexp_bignum_sign(x) < 0))) + +#define sexp_exact_negativep(x) \ + (sexp_ratiop(x) ? sexp_exact_integer_negativep(sexp_ratio_numerator(x)) \ + : sexp_exact_integer_negativep(x)) + +#define sexp_negativep(x) \ + (sexp_flonump(x) ? (sexp_flonum_value(x) < 0) \ + : sexp_hugenump(x) ? (sexp_exact_integer_negativep(sexp_hugenum_data(x)[0])) \ + : sexp_exact_negativep(x)) #define sexp_positivep(x) (!(sexp_negativep(x))) #if SEXP_USE_BIGNUMS @@ -801,9 +828,11 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #endif #define sexp_negate(x) \ - if (sexp_flonump(x)) \ + if (sexp_flonump(x)) { \ sexp_negate_flonum(x); \ - else \ + } else if (sexp_hugenump(x)) { \ + sexp_negate_exact(sexp_hugenum_data(x)[0]); \ + } else \ sexp_negate_exact(x) #if SEXP_USE_FLONUMS || SEXP_USE_BIGNUMS @@ -915,6 +944,9 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #define sexp_complex_real(q) (sexp_pred_field(q, complex, sexp_complexp, real)) #define sexp_complex_imag(q) (sexp_pred_field(q, complex, sexp_complexp, imag)) +#define sexp_hugenum_length(h) (sexp_pred_field(h, hugenum, sexp_hugenump, length)) +#define sexp_hugenum_data(h) (sexp_pred_field(h, hugenum, sexp_hugenump, data)) + #define sexp_exception_kind(x) (sexp_field(x, exception, SEXP_EXCEPTION, kind)) #define sexp_exception_message(x) (sexp_field(x, exception, SEXP_EXCEPTION, message)) #define sexp_exception_irritants(x) (sexp_field(x, exception, SEXP_EXCEPTION, irritants)) @@ -1342,13 +1374,13 @@ SEXP_API sexp sexp_display_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sex SEXP_API sexp sexp_flush_output_op (sexp ctx, sexp self, sexp_sint_t n, sexp out); SEXP_API sexp sexp_read_string (sexp ctx, sexp in, int sentinel); SEXP_API sexp sexp_read_symbol (sexp ctx, sexp in, int init, int internp); -SEXP_API sexp sexp_read_number (sexp ctx, sexp in, int base); +SEXP_API sexp sexp_read_number (sexp ctx, sexp in, int base, int exactp); #if SEXP_USE_BIGNUMS SEXP_API sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init, signed char sign, sexp_uint_t base); SEXP_API sexp sexp_write_bignum (sexp ctx, sexp a, sexp out, sexp_uint_t base); #endif -SEXP_API sexp sexp_read_float_tail(sexp ctx, sexp in, double whole, int negp); +SEXP_API sexp sexp_read_float_tail(sexp ctx, sexp in, double whole, int negp, int exactp); #if SEXP_USE_COMPLEX SEXP_API sexp sexp_read_complex_tail(sexp ctx, sexp in, sexp res); #endif @@ -192,7 +192,7 @@ _FN2OPT(_I(SEXP_OPORT), _I(SEXP_FIXNUM), _I(SEXP_BOOLEAN), "open-output-file-des _FN2OPT(_I(SEXP_OBJECT), _I(SEXP_PROCEDURE), _I(SEXP_FIXNUM), "register-optimization!", _I(600), sexp_register_optimization), #if SEXP_USE_MATH _FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "exp", 0, sexp_exp), -_FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "ln", 0, sexp_log), +_FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "ln", 0, sexp_log_op), _FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "sin", 0, sexp_sin), _FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "cos", 0, sexp_cos), _FN1(_I(SEXP_NUMBER), _I(SEXP_NUMBER), "tan", 0, sexp_tan), @@ -195,6 +195,9 @@ static struct sexp_type_struct _sexp_type_specs[] = { #if SEXP_USE_COMPLEX {SEXP_COMPLEX, sexp_offsetof(complex, real), 2, 2, 0, 0, sexp_sizeof(complex), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Complex", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, #endif +#if SEXP_USE_HUGENUMS + {SEXP_HUGENUM, sexp_offsetof(hugenum, data), 0, 0, sexp_offsetof(hugenum, length), 1, sexp_sizeof(hugenum), sexp_offsetof(hugenum, length), sizeof(sexp), 0, 0, 0, 0, 0, 0, (sexp)"Hugenum", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, +#endif {SEXP_IPORT, sexp_offsetof(port, name), 2, 2, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Input-Port", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, SEXP_FINALIZE_PORT}, {SEXP_OPORT, sexp_offsetof(port, name), 2, 2, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Output-Port", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, SEXP_FINALIZE_PORT}, {SEXP_FILENO, 0, 0, 0, 0, 0, sexp_sizeof(fileno), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"File-Descriptor", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, SEXP_FINALIZE_FILENO}, @@ -1939,6 +1942,20 @@ sexp sexp_write_one (sexp ctx, sexp obj, sexp out) { sexp_write_char(ctx, 'i', out); break; #endif +#if SEXP_USE_HUGENUMS + case SEXP_HUGENUM: + if (sexp_hugenum_length(obj) == 2 && sexp_hugenum_data(obj)[0] == SEXP_TEN) { + sexp_write_string(ctx, "1e", out); + sexp_write(ctx, sexp_hugenum_data(obj)[1], out); + } else { + sexp_write(ctx, sexp_hugenum_data(obj)[0], out); + for (i=1; i<sexp_hugenum_length(obj); i++) { + sexp_write_string(ctx, "->", out); + sexp_write(ctx, sexp_hugenum_data(obj)[i], out); + } + } + break; +#endif case SEXP_OPCODE: sexp_write_string(ctx, "#<opcode ", out); sexp_write(ctx, sexp_opcode_name(obj), out); @@ -2130,7 +2147,7 @@ sexp sexp_read_string (sexp ctx, sexp in, int sentinel) { case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'x': - res = sexp_read_number(ctx, in, 16); + res = sexp_read_number(ctx, in, 16, 1); if (sexp_fixnump(res)) { c = sexp_read_char(ctx, in); if (c != ';') { @@ -2244,9 +2261,12 @@ sexp sexp_complex_normalize (sexp cpx) { sexp sexp_read_complex_tail (sexp ctx, sexp in, sexp real) { int c = sexp_read_char(ctx, in), c2; +#if SEXP_USE_HUGENUMS + int i; +#endif sexp default_real = SEXP_ZERO; - sexp_gc_var1(res); - sexp_gc_preserve1(ctx, res); + sexp_gc_var2(res, tmp); + sexp_gc_preserve2(ctx, res, tmp); res = SEXP_VOID; if (c=='i' || c=='I') { /* trailing i, no sign */ trailing_i: @@ -2270,11 +2290,34 @@ sexp sexp_read_complex_tail (sexp ctx, sexp in, sexp real) { default_real = real; real = (c=='-') ? SEXP_NEG_ONE : SEXP_ONE; goto trailing_i; +#if SEXP_USE_HUGENUMS + } else if (c=='-' && c2=='>') { /* chained arrow */ + if (!sexp_exact_integerp(real)) { + res = sexp_read_error(ctx, "chains can only follow exact integers", real, in); + } else { + tmp = sexp_read_number(ctx, in, 10, 1); + if (real == SEXP_ONE || tmp == SEXP_ONE) { + res = real; + } else if (sexp_hugenump(tmp)) { + res = sexp_make_hugenum(ctx, sexp_hugenum_length(tmp)+1); + sexp_hugenum_data(res)[0] = real; + for (i=0; i<sexp_hugenum_length(tmp); i++) + sexp_hugenum_data(res)[i+1] = sexp_hugenum_data(tmp)[i]; + } else if (sexp_exact_integerp(tmp)) { + res = sexp_make_hugenum(ctx, 2); + sexp_hugenum_data(res)[0] = real; + sexp_hugenum_data(res)[1] = tmp; + } else { + res = sexp_exceptionp(tmp) ? tmp + : sexp_read_error(ctx, "invalid chained arrow component", tmp, in); + } + } +#endif } else { sexp_push_char(ctx, c2, in); /* read imaginary part */ if (c=='-') sexp_push_char(ctx, c, in); - res = sexp_read_number(ctx, in, 10); + res = sexp_read_number(ctx, in, 10, 0); if (sexp_complexp(res)) { if (sexp_complex_real(res) == SEXP_ZERO) sexp_complex_real(res) = real; @@ -2289,7 +2332,7 @@ sexp sexp_read_complex_tail (sexp ctx, sexp in, sexp real) { } } } - sexp_gc_release1(ctx); + sexp_gc_release2(ctx); return sexp_complex_normalize(res); } @@ -2297,7 +2340,7 @@ sexp sexp_read_complex_tail (sexp ctx, sexp in, sexp real) { sexp sexp_read_polar_tail (sexp ctx, sexp in, sexp magnitude) { sexp_gc_var2(res, theta); sexp_gc_preserve2(ctx, res, theta); - theta = sexp_read_number(ctx, in, 10); + theta = sexp_read_number(ctx, in, 10, 0); if (sexp_exceptionp(theta)) { res = theta; } else if (sexp_complexp(theta) || !sexp_numberp(theta)) { @@ -2315,12 +2358,11 @@ sexp sexp_read_polar_tail (sexp ctx, sexp in, sexp magnitude) { #endif #endif -sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { +sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp, int exactp) { int c, c2; - sexp exponent=SEXP_VOID; double val=0.0, scale=0.1, e=0.0; - sexp_gc_var1(res); - sexp_gc_preserve1(ctx, res); + sexp_gc_var2(res, exponent); + sexp_gc_preserve2(ctx, res, exponent); for (c=sexp_read_char(ctx, in); sexp_isdigit(c); c=sexp_read_char(ctx, in), scale*=0.1) val += digit_value(c)*scale; @@ -2333,9 +2375,9 @@ sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { if (is_precision_indicator(c)) { c2 = sexp_read_char(ctx, in); if (c2 != '+') sexp_push_char(ctx, c2, in); - exponent = sexp_read_number(ctx, in, 10); + exponent = sexp_read_number(ctx, in, 10, 1); if (sexp_exceptionp(exponent)) { - sexp_gc_release1(ctx); + sexp_gc_release2(ctx); return exponent; } #if SEXP_USE_COMPLEX @@ -2345,7 +2387,11 @@ sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { } #endif e = (sexp_fixnump(exponent) ? sexp_unbox_fixnum(exponent) - : sexp_flonump(exponent) ? sexp_flonum_value(exponent) : 0.0); + : sexp_flonump(exponent) ? sexp_flonum_value(exponent) +#if SEXP_USE_HUGENUMS + : (sexp_bignump(exponent) || sexp_hugenump(exponent)) ? (DBL_MAX_EXP+1) +#endif + : 0.0); #if SEXP_USE_COMPLEX if (sexp_complexp(res)) { if (sexp_complex_real(res) == SEXP_ZERO) { @@ -2353,17 +2399,44 @@ sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { } else { sexp_complex_real(res) = sexp_make_flonum(ctx, val * pow(10, e)); } - sexp_gc_release1(ctx); + sexp_gc_release2(ctx); return res; } #endif } - if (e != 0.0) val *= pow(10, e); + if (e != 0.0) { +#if SEXP_USE_BIGNUMS + if (exactp && (val == trunc(val))) { + res = sexp_make_integer(ctx, (sexp_sint_t)val); + exponent = sexp_expt(ctx, SEXP_TEN, exponent); + res = sexp_mul(ctx, res, exponent); + sexp_gc_release2(ctx); + return res; + } else +#endif + val *= pow(10, e); + } +#if SEXP_USE_HUGENUMS + if (isinf(val)) { + if (sexp_hugenump(exponent)) { + res = sexp_expt(ctx, SEXP_TEN, exponent); + } else { + res = sexp_make_hugenum(ctx, 2); + if (sexp_flonump(exponent)) { + sexp_hugenum_data(res)[1] = sexp_flonum_value(exponent) > SEXP_MAX_FIXNUM ? sexp_double_to_bignum(ctx, sexp_flonum_value(exponent)) : sexp_make_fixnum((sexp_sint_t)sexp_flonum_value(exponent)); + } else { + sexp_hugenum_data(res)[1] = exponent; + } + sexp_hugenum_data(res)[0] = SEXP_TEN; + } + } else +#endif #if SEXP_USE_FLONUMS - res = sexp_make_flonum(ctx, val); -#else - res = sexp_make_fixnum((sexp_uint_t)val); + if (!exactp) + res = sexp_make_flonum(ctx, val); + else #endif + res = sexp_make_fixnum((sexp_sint_t)val); if (!is_precision_indicator(c)) { #if SEXP_USE_COMPLEX if (c=='i' || c=='i' || c=='+' || c=='-') { @@ -2377,7 +2450,7 @@ sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { else sexp_push_char(ctx, c, in); } - sexp_gc_release1(ctx); + sexp_gc_release2(ctx); return res; } @@ -2422,7 +2495,7 @@ sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in) { } #endif -sexp sexp_read_number (sexp ctx, sexp in, int base) { +sexp sexp_read_number (sexp ctx, sexp in, int base, int exactp) { sexp_sint_t val = 0, tmp = -1; int c, digit, negativep = 0; #if SEXP_USE_PLACEHOLDER_DIGITS @@ -2467,7 +2540,7 @@ sexp sexp_read_number (sexp ctx, sexp in, int base) { whole += sexp_placeholder_digit_value(10)*scale; if (is_precision_indicator(c)) { sexp_push_char(ctx, c, in); - return sexp_read_float_tail(ctx, in, whole, negativep); + return sexp_read_float_tail(ctx, in, whole, negativep, exactp); } else if ((c!=EOF) && !sexp_is_separator(c)) { return sexp_read_error(ctx, "invalid numeric syntax after placeholders", sexp_make_character(c), in); @@ -2481,10 +2554,10 @@ sexp sexp_read_number (sexp ctx, sexp in, int base) { if (base != 10) return sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in); if (c!='.') sexp_push_char(ctx, c, in); - return sexp_read_float_tail(ctx, in, val, negativep); + return sexp_read_float_tail(ctx, in, val, negativep, exactp); } else if (c=='/') { sexp_gc_preserve2(ctx, res, den); - den = sexp_read_number(ctx, in, base); + den = sexp_read_number(ctx, in, base, 1); if (! (sexp_fixnump(den) || sexp_bignump(den) || sexp_complexp(den))) res = (sexp_exceptionp(den) ? den : sexp_read_error(ctx, "invalid rational syntax", den, in)); @@ -2705,15 +2778,31 @@ sexp sexp_read_raw (sexp ctx, sexp in) { case '#': switch (c1=sexp_read_char(ctx, in)) { case 'b': case 'B': - res = sexp_read_number(ctx, in, 2); break; + res = sexp_read_number(ctx, in, 2, 0); break; case 'o': case 'O': - res = sexp_read_number(ctx, in, 8); break; + res = sexp_read_number(ctx, in, 8, 0); break; case 'd': case 'D': - res = sexp_read_number(ctx, in, 10); break; + res = sexp_read_number(ctx, in, 10, 0); break; case 'x': case 'X': - res = sexp_read_number(ctx, in, 16); break; + res = sexp_read_number(ctx, in, 16, 0); break; case 'e': case 'E': - res = sexp_read(ctx, in); + if ((c1=sexp_read_char(ctx, in)) == '#') { + switch (c2=sexp_read_char(ctx, in)) { + case 'b': case 'B': + res = sexp_read_number(ctx, in, 2, 1); break; + case 'o': case 'O': + res = sexp_read_number(ctx, in, 8, 1); break; + case 'd': case 'D': + res = sexp_read_number(ctx, in, 10, 1); break; + case 'x': case 'X': + res = sexp_read_number(ctx, in, 16, 1); break; + default: + res = sexp_read_error(ctx, "invalid numeric syntax after #e#", sexp_make_character(c2), in); break; + } + } else { + sexp_push_char(ctx, c1, in); + res = sexp_read_number(ctx, in, 10, 1); + } #if SEXP_USE_INFINITIES if (sexp_flonump(res) && (isnan(sexp_flonum_value(res)) || isinf(sexp_flonum_value(res)))) @@ -2841,7 +2930,7 @@ sexp sexp_read_raw (sexp ctx, sexp in) { c2 = sexp_read_char(ctx, in); sexp_push_char(ctx, c2, in); if ((c1 == 'x' || c1 == 'X') && (sexp_isxdigit(c2))) { - res = sexp_read_number(ctx, in, 16); + res = sexp_read_number(ctx, in, 16, 1); if (sexp_fixnump(res) && sexp_unbox_fixnum(res) >= 0 && sexp_unbox_fixnum(res) <= 0x10FFFF) res = sexp_make_character(sexp_unbox_fixnum(res)); else if (!sexp_exceptionp(res)) @@ -2902,7 +2991,7 @@ sexp sexp_read_raw (sexp ctx, sexp in) { if (c1 == EOF || sexp_is_separator(c1)) { res = SEXP_RAWDOT; } else if (sexp_isdigit(c1)) { - res = sexp_read_float_tail(ctx, in, 0, 0); + res = sexp_read_float_tail(ctx, in, 0, 0, 0); } else { res = sexp_read_symbol(ctx, in, '.', 1); } @@ -2925,7 +3014,7 @@ sexp sexp_read_raw (sexp ctx, sexp in) { c2 = sexp_read_char(ctx, in); if (c2 == '.' || sexp_isdigit(c2)) { sexp_push_char(ctx, c2, in); - res = sexp_read_number(ctx, in, 10); + res = sexp_read_number(ctx, in, 10, 0); if ((c1 == '-') && ! sexp_exceptionp(res)) { #if SEXP_USE_FLONUMS if (sexp_flonump(res)) @@ -2959,6 +3048,11 @@ sexp sexp_read_raw (sexp ctx, sexp in) { } } else #endif +#if SEXP_USE_HUGENUMS + if (sexp_hugenump(res)) { + sexp_negate(sexp_hugenum_data(res)[0]); + } else +#endif res = sexp_fx_mul(res, SEXP_NEG_ONE); } } else { @@ -3007,7 +3101,7 @@ sexp sexp_read_raw (sexp ctx, sexp in) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': sexp_push_char(ctx, c1, in); - res = sexp_read_number(ctx, in, 10); + res = sexp_read_number(ctx, in, 10, 0); break; default: res = sexp_read_symbol(ctx, in, c1, 1); @@ -3065,7 +3159,7 @@ sexp sexp_string_to_number_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sex sexp_read_char(ctx, in); } in = ((sexp_string_data(str)[0] == '#') || base == 10 ? - sexp_read(ctx, in) : sexp_read_number(ctx, in, base)); + sexp_read(ctx, in) : sexp_read_number(ctx, in, base, 0)); sexp_gc_release1(ctx); return sexp_numberp(in) ? in : SEXP_FALSE; } |