diff --git a/eval.c b/eval.c index aedd5356..47ba5042 100644 --- a/eval.c +++ b/eval.c @@ -1142,6 +1142,13 @@ sexp sexp_register_optimization (sexp ctx sexp_api_params(self, n), sexp f, sexp #define maybe_convert_bignum(z) #endif +#if SEXP_USE_RATIOS +#define maybe_convert_ratio(z) \ + else if (sexp_ratiop(z)) d = sexp_ratio_to_double(z); +#else +#define maybe_convert_ratio(z) +#endif + #define define_math_op(name, cname) \ static sexp name (sexp ctx sexp_api_params(self, n), sexp z) { \ double d; \ @@ -1149,6 +1156,7 @@ sexp sexp_register_optimization (sexp ctx sexp_api_params(self, n), sexp f, sexp d = sexp_flonum_value(z); \ else if (sexp_fixnump(z)) \ d = (double)sexp_unbox_fixnum(z); \ + maybe_convert_ratio(z) \ maybe_convert_bignum(z) \ else \ return sexp_type_exception(ctx, self, SEXP_NUMBER, z); \ @@ -1243,6 +1251,17 @@ static sexp sexp_expt_op (sexp ctx sexp_api_params(self, n), sexp x, sexp e) { return res; } +#if SEXP_USE_RATIOS +static sexp sexp_ratio_numerator_op (sexp ctx sexp_api_params(self, n), sexp rat) { + sexp_assert_type(ctx, sexp_ratiop, SEXP_RATIO, rat); + return sexp_ratio_numerator(rat); +} +static sexp sexp_ratio_denominator_op (sexp ctx sexp_api_params(self, n), sexp rat) { + sexp_assert_type(ctx, sexp_ratiop, SEXP_RATIO, rat); + return sexp_ratio_denominator(rat); +} +#endif + static sexp sexp_string_cmp_op (sexp ctx sexp_api_params(self, n), sexp str1, sexp str2, sexp ci) { sexp_sint_t len1, len2, len, diff; sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str1); @@ -1785,6 +1804,9 @@ sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) { #endif #if SEXP_USE_AUTO_FORCE sexp_push(ctx, tmp, sym=sexp_intern(ctx, "auto-force", -1)); +#endif +#if SEXP_USE_RATIOS + sexp_push(ctx, tmp, sym=sexp_intern(ctx, "ratios", -1)); #endif sexp_push(ctx, tmp, sym=sexp_intern(ctx, "chibi", -1)); sexp_env_define(ctx, e, sym=sexp_intern(ctx, "*features*", -1), tmp); diff --git a/include/chibi/bignum.h b/include/chibi/bignum.h index 9c6ede07..03b416d4 100644 --- a/include/chibi/bignum.h +++ b/include/chibi/bignum.h @@ -1,6 +1,6 @@ -/* bignum.h -- header for bignum utilities */ -/* Copyright (c) 2009 Alex Shinn. All rights reserved. */ -/* BSD-style license: http://synthcode.com/license.txt */ +/* bignum.h -- header for bignum utilities */ +/* Copyright (c) 2009-2011 Alex Shinn. All rights reserved. */ +/* BSD-style license: http://synthcode.com/license.txt */ #ifndef SEXP_BIGNUM_H #define SEXP_BIGNUM_H @@ -38,6 +38,11 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b); sexp sexp_div (sexp ctx, sexp a, sexp b); sexp sexp_quotient (sexp ctx, sexp a, sexp b); sexp sexp_remainder (sexp ctx, sexp a, sexp b); +#if SEXP_USE_RATIOS +double sexp_ratio_to_double (sexp rat); +sexp sexp_make_ratio (sexp ctx, sexp num, sexp den); +sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in); +#endif #endif /* ! SEXP_BIGNUM_H */ diff --git a/include/chibi/features.h b/include/chibi/features.h index 716e7431..08bc157c 100644 --- a/include/chibi/features.h +++ b/include/chibi/features.h @@ -117,6 +117,13 @@ /* in opt/bignum.c. */ /* #define SEXP_USE_BIGNUMS 0 */ +/* uncomment this if you don't want exact ratio support */ +/* Ratios are part of the bignum library and imply bignums. */ +/* #define SEXP_USE_RATIOS 0 */ + +/* uncomment this if you don't want imaginary number support */ +/* #define SEXP_USE_COMPLEX 0 */ + /* uncomment this if you don't want 1## style approximate digits */ /* #define SEXP_USE_PLACEHOLDER_DIGITS 0 */ @@ -354,6 +361,19 @@ #define SEXP_USE_EXTENDED_FCALL ! SEXP_USE_NO_FEATURES #endif +#ifndef SEXP_USE_RATIOS +#define SEXP_USE_RATIOS ! SEXP_USE_NO_FEATURES +#endif + +/* #ifndef SEXP_USE_COMPLEX */ +/* #define SEXP_USE_COMPLEX ! SEXP_USE_NO_FEATURES */ +/* #endif */ +#define SEXP_USE_COMPLEX 0 + +#ifndef SEXP_USE_BIGNUMS +#define SEXP_USE_BIGNUMS (SEXP_USE_RATIOS || SEXP_USE_COMPLEX) +#endif + #ifndef SEXP_USE_FLONUMS #define SEXP_USE_FLONUMS ! SEXP_USE_NO_FEATURES #endif @@ -378,10 +398,6 @@ #define SEXP_PLACEHOLDER_DIGIT '#' #endif -#ifndef SEXP_USE_BIGNUMS -#define SEXP_USE_BIGNUMS ! SEXP_USE_NO_FEATURES -#endif - #ifndef SEXP_USE_MATH #define SEXP_USE_MATH SEXP_USE_FLONUMS && ! SEXP_USE_NO_FEATURES #endif diff --git a/include/chibi/sexp.h b/include/chibi/sexp.h index 65add36e..480280b1 100755 --- a/include/chibi/sexp.h +++ b/include/chibi/sexp.h @@ -103,6 +103,8 @@ enum sexp_types { SEXP_VECTOR, SEXP_FLONUM, SEXP_BIGNUM, + SEXP_RATIO, + SEXP_COMPLEX, SEXP_IPORT, SEXP_OPORT, SEXP_EXCEPTION, @@ -300,6 +302,12 @@ struct sexp_struct { sexp_uint_t length; sexp_uint_t data[]; } bignum; + struct { + sexp numerator, denominator; + } ratio; + struct { + sexp real, imag; + } complex; struct { sexp_uint_t length; void *value; @@ -553,6 +561,8 @@ sexp sexp_make_flonum(sexp ctx, double f); #define sexp_iportp(x) (sexp_check_tag(x, SEXP_IPORT)) #define sexp_oportp(x) (sexp_check_tag(x, SEXP_OPORT)) #define sexp_bignump(x) (sexp_check_tag(x, SEXP_BIGNUM)) +#define sexp_ratiop(x) (sexp_check_tag(x, SEXP_RATIO)) +#define sexp_complexp(x) (sexp_check_tag(x, SEXP_COMPLEX)) #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)) @@ -646,6 +656,18 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #define sexp_numberp(x) sexp_exact_integerp(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_negate(x) \ + if (sexp_bignump(x)) \ + sexp_bignum_sign(x) = -sexp_bignum_sign(x); \ + else if (sexp_fixnump(x)) \ + x = sexp_fx_neg(x); + #if SEXP_USE_FLONUMS || SEXP_USE_BIGNUMS #define sexp_uint_value(x) ((sexp_uint_t)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignum_data(x)[0])) #define sexp_sint_value(x) ((sexp_sint_t)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignum_sign(x)*sexp_bignum_data(x)[0])) @@ -723,6 +745,12 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); #define sexp_port_offset(p) (sexp_pred_field(p, port, sexp_portp, offset)) #define sexp_port_flags(p) (sexp_pred_field(p, port, sexp_portp, flags)) +#define sexp_ratio_numerator(q) (sexp_pred_field(q, ratio, sexp_ratiop, numerator)) +#define sexp_ratio_denominator(q) (sexp_pred_field(q, ratio, sexp_ratiop, denominator)) + +#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_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)) diff --git a/lib/init.scm b/lib/init.scm index f8984e4b..8ff79c19 100644 --- a/lib/init.scm +++ b/lib/init.scm @@ -350,6 +350,26 @@ ;; string utils +(define (digit-char n) + (if (<= n 9) + (integer->char (+ n (char->integer #\0))) + (integer->char (+ (- n 10) (char->integer #\A))))) +(define (digit-value ch) + (if (char-numeric? ch) + (- (char->integer ch) (char->integer #\0)) + (and (<= 65 (char->integer (char-upcase ch)) 70) + (- (char->integer (char-upcase ch)) 55)))) + +(define (number->string num . o) + (if (if (null? o) #t (eq? 10 (car o))) + (call-with-output-string (lambda (out) (write num out))) + (let lp ((n (abs num)) (d (car o)) (res '())) + (if (> n 0) + (lp (quotient n d) d (cons (digit-char (remainder n d)) res)) + (if (null? res) + "0" + (list->string (if (negative? num) (cons #\- res) res))))))) + (define (symbol->string sym) (call-with-output-string (lambda (out) (write sym out)))) @@ -413,93 +433,6 @@ (define (find pred ls) (cond ((find-tail pred ls) => car) (else #f))) -;; math utils - -(define (number? x) (if (fixnum? x) #t (if (bignum? x) #t (flonum? x)))) -(define complex? number?) -(define rational? number?) -(define real? number?) -(define (exact? x) (if (fixnum? x) #t (bignum? x))) -(define inexact? flonum?) -(define (exact-integer? x) (if (fixnum? x) #t (bignum? x))) -(define (integer? x) - (if (exact-integer? x) #t (and (flonum? x) (= x (truncate x))))) - -(define (exact-integer-sqrt x) - (let ((res (sqrt x))) - (if (exact? res) - (values res 0) - (let ((res (inexact->exact (truncate res)))) - (values res (- x (* res res))))))) - -(define (zero? x) (= x 0)) -(define (positive? x) (> x 0)) -(define (negative? x) (< x 0)) -(define (even? n) (= (remainder n 2) 0)) -(define (odd? n) (= (remainder n 2) 1)) - -(define (abs x) (if (< x 0) (- x) x)) - -(define (numerator x) - (if (integer? x) x (numerator (* x 10)))) -(define (denominator x) - (if (exact? x) - 1 - (let lp ((x x) (r 1.0)) (if (integer? x) r (lp (* x 10) (* r 10)))))) - -(define (modulo a b) - (let ((res (remainder a b))) - (if (< b 0) - (if (<= res 0) res (+ res b)) - (if (>= res 0) res (+ res b))))) - -(define (gcd a b) - (if (= b 0) - (abs a) - (gcd b (remainder a b)))) - -(define (lcm a b) - (abs (quotient (* a b) (gcd a b)))) - -(define (max x . rest) - (let lp ((hi x) (ls rest)) - (if (null? ls) - hi - (lp (if (> (car ls) hi) (car ls) hi) (cdr ls))))) - -(define (min x . rest) - (let lp ((lo x) (ls rest)) - (if (null? ls) - lo - (lp (if (< (car ls) lo) (car ls) lo) (cdr ls))))) - -(define (real-part z) z) -(define (imag-part z) 0.0) -(define magnitude abs) -(define (angle z) (if (< z 0) 3.141592653589793 0)) - -(define (atan x . o) (if (null? o) (atan1 x) (atan1 (/ x (car o))))) - -(define (digit-char n) - (if (<= n 9) - (integer->char (+ n (char->integer #\0))) - (integer->char (+ (- n 10) (char->integer #\A))))) -(define (digit-value ch) - (if (char-numeric? ch) - (- (char->integer ch) (char->integer #\0)) - (and (<= 65 (char->integer (char-upcase ch)) 70) - (- (char->integer (char-upcase ch)) 55)))) - -(define (number->string num . o) - (if (if (null? o) #t (eq? 10 (car o))) - (call-with-output-string (lambda (out) (write num out))) - (let lp ((n (abs num)) (d (car o)) (res '())) - (if (> n 0) - (lp (quotient n d) d (cons (digit-char (remainder n d)) res)) - (if (null? res) - "0" - (list->string (if (negative? num) (cons #\- res) res))))))) - ;; vector utils (define (list->vector ls) @@ -955,6 +888,86 @@ result))) (define (force x) (if (procedure? x) (x) x)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; math utils + +(cond-expand + (ratios + (define (exact? x) (if (fixnum? x) #t (if (bignum? x) #t (ratio? x)))) + (define (numerator x) + (if (ratio? x) + (ratio-numerator x) + (if (integer? x) x (numerator (* x 10))))) + (define (denominator x) + (if (exact? x) + (if (ratio? x) (ratio-denominator x) 1) + (let lp ((x x) (r 1.0)) (if (integer? x) r (lp (* x 10) (* r 10))))))) + (else + (define (exact? x) (if (fixnum? x) #t (bignum? x))) + (define (numerator x) + (if (integer? x) x (numerator (* x 10)))) + (define (denominator x) + (if (exact? x) + 1 + (let lp ((x x) (r 1.0)) (if (integer? x) r (lp (* x 10) (* r 10)))))))) + +(define inexact? flonum?) +(define (exact-integer? x) (if (fixnum? x) #t (bignum? x))) +(define (integer? x) + (if (exact-integer? x) #t (and (flonum? x) (= x (truncate x))))) +(define (number? x) (if (inexact? x) #t (exact? x))) +(define complex? number?) +(define rational? number?) +(define real? number?) + +(define (exact-integer-sqrt x) + (let ((res (sqrt x))) + (if (exact? res) + (values res 0) + (let ((res (inexact->exact (truncate res)))) + (values res (- x (* res res))))))) + +(define (zero? x) (= x 0)) +(define (positive? x) (> x 0)) +(define (negative? x) (< x 0)) +(define (even? n) (= (remainder n 2) 0)) +(define (odd? n) (= (remainder n 2) 1)) + +(define (abs x) (if (< x 0) (- x) x)) + +(define (modulo a b) + (let ((res (remainder a b))) + (if (< b 0) + (if (<= res 0) res (+ res b)) + (if (>= res 0) res (+ res b))))) + +(define (gcd a b) + (if (= b 0) + (abs a) + (gcd b (remainder a b)))) + +(define (lcm a b) + (abs (quotient (* a b) (gcd a b)))) + +(define (max x . rest) + (let lp ((hi x) (ls rest)) + (if (null? ls) + hi + (lp (if (> (car ls) hi) (car ls) hi) (cdr ls))))) + +(define (min x . rest) + (let lp ((lo x) (ls rest)) + (if (null? ls) + lo + (lp (if (< (car ls) lo) (car ls) lo) (cdr ls))))) + +(define (real-part z) z) +(define (imag-part z) 0.0) +(define magnitude abs) +(define (angle z) (if (< z 0) 3.141592653589793 0)) + +(define (atan x . o) (if (null? o) (atan1 x) (atan1 (/ x (car o))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; string cursors diff --git a/opcodes.c b/opcodes.c index dc2937dc..6f812e4e 100644 --- a/opcodes.c +++ b/opcodes.c @@ -82,6 +82,11 @@ _FN1(_I(SEXP_BOOLEAN), _I(SEXP_OBJECT), "flonum?", 0, sexp_flonump_op), _OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "flonum?", _I(SEXP_FLONUM), 0), #endif _OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "bignum?", _I(SEXP_BIGNUM), 0), +#if SEXP_USE_RATIOS +_OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "ratio?", _I(SEXP_RATIO), 0), +_FN1(_I(SEXP_FIXNUM), _I(SEXP_RATIO), "ratio-numerator", 0, sexp_ratio_numerator_op), +_FN1(_I(SEXP_FIXNUM), _I(SEXP_RATIO), "ratio-denominator", 0, sexp_ratio_denominator_op), +#endif _OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "closure?", _I(SEXP_PROCEDURE), 0), _OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "opcode?", _I(SEXP_OPCODE), 0), _OP(SEXP_OPC_TYPE_PREDICATE, SEXP_OP_TYPEP, 1, 0, _I(SEXP_BOOLEAN), _I(SEXP_OBJECT), SEXP_FALSE, SEXP_FALSE, 0, "input-port?", _I(SEXP_IPORT), 0), diff --git a/opt/bignum.c b/opt/bignum.c index f68f4821..b347706d 100644 --- a/opt/bignum.c +++ b/opt/bignum.c @@ -1,15 +1,9 @@ /* bignum.c -- bignum support */ -/* Copyright (c) 2009-2010 Alex Shinn. All rights reserved. */ +/* Copyright (c) 2009-2011 Alex Shinn. All rights reserved. */ /* BSD-style license: http://synthcode.com/license.txt */ #define SEXP_INIT_BIGNUM_SIZE 2 -#define sexp_negate(x) \ - if (sexp_bignump(x)) \ - sexp_bignum_sign(x) = -sexp_bignum_sign(x); \ - else if (sexp_fixnump(x)) \ - x = sexp_fx_neg(x); - sexp sexp_make_bignum (sexp ctx, sexp_uint_t len) { sexp_uint_t size = sexp_sizeof(bignum) + len*sizeof(sexp_uint_t); sexp res = sexp_alloc_tagged(ctx, size, SEXP_BIGNUM); @@ -229,6 +223,13 @@ sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init, 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)); } +#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); + res = sexp_ratio_normalize(ctx, res, in); +#endif } else if ((c!=EOF) && ! is_separator(c)) { res = sexp_read_error(ctx, "invalid numeric syntax", sexp_make_character(c), in); @@ -458,13 +459,71 @@ sexp sexp_bignum_expt (sexp ctx, sexp a, sexp b) { return sexp_bignum_normalize(res); } +/************************ ratios ******************************/ + +#if SEXP_USE_RATIOS + +double sexp_ratio_to_double (sexp rat) { + sexp num = sexp_ratio_numerator(rat), den = sexp_ratio_denominator(rat); + return (sexp_bignump(num) ? sexp_bignum_to_double(num) + : sexp_fixnum_to_double(num)) + / (sexp_bignump(den) ? sexp_bignum_to_double(den) + : sexp_fixnum_to_double(den)); +} + +sexp sexp_ratio_add (sexp ctx, sexp a, sexp b) { + sexp_gc_var3(res, num, den); + sexp_gc_preserve3(ctx, res, num, den); + num = sexp_mul(ctx, sexp_ratio_numerator(a), sexp_ratio_denominator(b)); + den = sexp_mul(ctx, sexp_ratio_numerator(b), sexp_ratio_denominator(a)); + num = sexp_add(ctx, num, den); + den = sexp_mul(ctx, sexp_ratio_denominator(a), sexp_ratio_denominator(b)); + res = sexp_make_ratio(ctx, num, den); + sexp_gc_release3(ctx); + return sexp_ratio_normalize(ctx, res, SEXP_FALSE); +} + +sexp sexp_ratio_mul (sexp ctx, sexp a, sexp b) { + sexp_gc_var3(res, num, den); + sexp_gc_preserve3(ctx, res, num, den); + num = sexp_mul(ctx, sexp_ratio_numerator(a), sexp_ratio_numerator(b)); + den = sexp_mul(ctx, sexp_ratio_denominator(a), sexp_ratio_denominator(b)); + res = sexp_make_ratio(ctx, num, den); + sexp_gc_release3(ctx); + return sexp_ratio_normalize(ctx, res, SEXP_FALSE); +} + +sexp sexp_ratio_div (sexp ctx, sexp a, sexp b) { + sexp_gc_var3(res, num, den); + sexp_gc_preserve3(ctx, res, num, den); + num = sexp_mul(ctx, sexp_ratio_numerator(a), sexp_ratio_denominator(b)); + den = sexp_mul(ctx, sexp_ratio_denominator(a), sexp_ratio_numerator(b)); + res = sexp_make_ratio(ctx, num, den); + sexp_gc_release3(ctx); + return sexp_ratio_normalize(ctx, res, SEXP_FALSE); +} + +sexp sexp_ratio_compare (sexp ctx, sexp a, sexp b) { + sexp_gc_var2(a2, b2); + sexp_gc_preserve2(ctx, a2, b2); + a2 = sexp_mul(ctx, sexp_ratio_numerator(a), sexp_ratio_denominator(b)); + b2 = sexp_mul(ctx, sexp_ratio_numerator(b), sexp_ratio_denominator(a)); + a2 = sexp_compare(ctx, a2, b2); + sexp_gc_release2(ctx); + return a2; +} + +#endif + /****************** generic arithmetic ************************/ enum sexp_number_types { SEXP_NUM_NOT = 0, SEXP_NUM_FIX, SEXP_NUM_FLO, - SEXP_NUM_BIG + SEXP_NUM_BIG, + SEXP_NUM_RAT, + SEXP_NUM_CPX, }; enum sexp_number_combs { @@ -472,22 +531,68 @@ enum sexp_number_combs { SEXP_NUM_NOT_FIX, SEXP_NUM_NOT_FLO, SEXP_NUM_NOT_BIG, +#if SEXP_USE_RATIOS + SEXP_NUM_NOT_RAT, +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_NOT_CPX, +#endif SEXP_NUM_FIX_NOT, SEXP_NUM_FIX_FIX, SEXP_NUM_FIX_FLO, SEXP_NUM_FIX_BIG, +#if SEXP_USE_RATIOS + SEXP_NUM_FIX_RAT, +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_FIX_CPX, +#endif SEXP_NUM_FLO_NOT, SEXP_NUM_FLO_FIX, SEXP_NUM_FLO_FLO, SEXP_NUM_FLO_BIG, +#if SEXP_USE_RATIOS + SEXP_NUM_FLO_RAT, +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_FLO_CPX, +#endif SEXP_NUM_BIG_NOT, SEXP_NUM_BIG_FIX, SEXP_NUM_BIG_FLO, - SEXP_NUM_BIG_BIG + SEXP_NUM_BIG_BIG, +#if SEXP_USE_RATIOS + SEXP_NUM_BIG_RAT, +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_BIG_CPX, +#endif +#if SEXP_USE_RATIOS + SEXP_NUM_RAT_NOT, + SEXP_NUM_RAT_FIX, + SEXP_NUM_RAT_FLO, + SEXP_NUM_RAT_BIG, + SEXP_NUM_RAT_RAT, +#if SEXP_USE_COMPLEX + SEXP_NUM_RAT_CPX, +#endif +#endif +#if SEXP_USE_COMPLEX + SEXP_NUM_CPX_NOT, + SEXP_NUM_CPX_FIX, + SEXP_NUM_CPX_FLO, + SEXP_NUM_CPX_BIG, +#if SEXP_USE_RATIOS + SEXP_NUM_CPX_RAT, +#endif + SEXP_NUM_CPX_CPX, +#endif }; static int sexp_number_types[] = - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0}; + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 0, 0}; + +#define SEXP_NUM_NUMBER_TYPES (4 + SEXP_USE_RATIOS + SEXP_USE_COMPLEX) static int sexp_number_type (sexp a) { return sexp_pointerp(a) ? sexp_number_types[sexp_pointer_tag(a)&15] @@ -500,10 +605,15 @@ static int sexp_number_type (sexp a) { sexp sexp_add (sexp ctx, sexp a, sexp b) { int at=sexp_number_type(a), bt=sexp_number_type(b), t; sexp r=SEXP_VOID; + sexp_gc_var1(tmp); + sexp_gc_preserve1(ctx, tmp); if (at > bt) {r=a; a=b; b=r; t=at; at=bt; bt=t;} - switch ((at << 2) + bt) { + 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 r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_FIX: @@ -524,21 +634,40 @@ sexp sexp_add (sexp ctx, sexp a, sexp b) { case SEXP_NUM_BIG_BIG: r = sexp_bignum_normalize(sexp_bignum_add(ctx, NULL, b, a)); break; +#if SEXP_USE_RATIOS + case SEXP_NUM_FLO_RAT: + r = sexp_make_flonum(ctx, sexp_flonum_value(a) + sexp_ratio_to_double(b)); + break; + case SEXP_NUM_FIX_RAT: + case SEXP_NUM_BIG_RAT: + a = tmp = sexp_make_ratio(ctx, a, SEXP_ONE); + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_RAT: + r = sexp_ratio_add(ctx, a, b); + break; +#endif } + sexp_gc_release1(ctx); return r; } sexp sexp_sub (sexp ctx, sexp a, sexp b) { - int at=sexp_number_type(a), bt=sexp_number_type(b); + int at=sexp_number_type(a), bt=sexp_number_type(b), negatep=0; sexp r=SEXP_VOID; - sexp_gc_var1(tmp); - sexp_gc_preserve1(ctx, tmp); - switch ((at << 2) + bt) { + sexp_gc_var2(tmp1, tmp2); + sexp_gc_preserve2(ctx, tmp1, tmp2); + 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 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 r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, b); break; case SEXP_NUM_FIX_FIX: @@ -548,8 +677,8 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) { r = sexp_make_flonum(ctx, sexp_fixnum_to_double(a)-sexp_flonum_value(b)); break; case SEXP_NUM_FIX_BIG: - tmp = sexp_fixnum_to_bignum(ctx, a); - r = sexp_bignum_sub(ctx, NULL, b, tmp); + tmp1 = sexp_fixnum_to_bignum(ctx, a); + r = sexp_bignum_sub(ctx, NULL, b, tmp1); sexp_negate(r); r = sexp_bignum_normalize(r); break; @@ -563,8 +692,8 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) { r = sexp_make_flonum(ctx, sexp_flonum_value(a) - sexp_bignum_to_double(b)); break; case SEXP_NUM_BIG_FIX: - tmp = sexp_fixnum_to_bignum(ctx, b); - r = sexp_bignum_normalize(sexp_bignum_sub(ctx, NULL, a, tmp)); + tmp1 = sexp_fixnum_to_bignum(ctx, b); + r = sexp_bignum_normalize(sexp_bignum_sub(ctx, NULL, a, tmp1)); break; case SEXP_NUM_BIG_FLO: r = sexp_make_flonum(ctx, sexp_bignum_to_double(a) - sexp_flonum_value(b)); @@ -572,18 +701,52 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) { case SEXP_NUM_BIG_BIG: r = sexp_bignum_normalize(sexp_bignum_sub(ctx, NULL, a, b)); break; +#if SEXP_USE_RATIOS + case SEXP_NUM_FLO_RAT: + r = sexp_make_flonum(ctx, sexp_flonum_value(a) - sexp_ratio_to_double(b)); + break; + case SEXP_NUM_RAT_FLO: + r = sexp_make_flonum(ctx, sexp_ratio_to_double(b) - sexp_flonum_value(a)); + break; + case SEXP_NUM_RAT_FIX: + case SEXP_NUM_RAT_BIG: + tmp1 = a; a = b; b = tmp1; + negatep = 1; + /* ... FALLTHROUGH ... */ + case SEXP_NUM_FIX_RAT: + case SEXP_NUM_BIG_RAT: + a = tmp1 = sexp_make_ratio(ctx, a, SEXP_ONE); + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_RAT: + tmp2 = sexp_make_ratio(ctx, sexp_ratio_numerator(b), sexp_ratio_denominator(b)); + sexp_negate(sexp_ratio_numerator(tmp2)); + r = sexp_ratio_add(ctx, a, tmp2); + if (negatep) { + if (sexp_ratiop(r)) { + sexp_negate(sexp_ratio_numerator(r)); + } else { + sexp_negate(r); + } + } + break; +#endif } - sexp_gc_release1(ctx); + sexp_gc_release2(ctx); return r; } sexp sexp_mul (sexp ctx, sexp a, sexp b) { int at=sexp_number_type(a), bt=sexp_number_type(b), t; sexp r=SEXP_VOID; + sexp_gc_var1(tmp); + sexp_gc_preserve1(ctx, tmp); if (at > bt) {r=a; a=b; b=r; t=at; at=bt; bt=t;} - switch ((at << 2) + bt) { + 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 r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); break; case SEXP_NUM_FIX_FIX: @@ -605,7 +768,20 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) { case SEXP_NUM_BIG_BIG: r = sexp_bignum_mul(ctx, NULL, a, b); break; +#if SEXP_USE_RATIOS + case SEXP_NUM_FLO_RAT: + r = sexp_make_flonum(ctx, sexp_flonum_value(a) * sexp_ratio_to_double(b)); + break; + case SEXP_NUM_FIX_RAT: + case SEXP_NUM_BIG_RAT: + a = tmp = sexp_make_ratio(ctx, a, SEXP_ONE); + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_RAT: + r = sexp_ratio_mul(ctx, a, b); + break; +#endif } + sexp_gc_release1(ctx); return r; } @@ -615,12 +791,18 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) { sexp r=SEXP_VOID; sexp_gc_var2(tmp, rem); sexp_gc_preserve2(ctx, tmp, rem); - switch ((at << 2) + bt) { + 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 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 r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, b); break; case SEXP_NUM_FIX_FIX: @@ -657,6 +839,25 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) { case SEXP_NUM_BIG_FLO: r = sexp_make_flonum(ctx, sexp_bignum_to_double(a) / sexp_flonum_value(b)); break; +#if SEXP_USE_RATIOS + case SEXP_NUM_FLO_RAT: + r = sexp_make_flonum(ctx, sexp_flonum_value(a) / sexp_ratio_to_double(b)); + break; + case SEXP_NUM_RAT_FLO: + r = sexp_make_flonum(ctx, sexp_ratio_to_double(b) / sexp_flonum_value(a)); + break; + case SEXP_NUM_RAT_FIX: + case SEXP_NUM_RAT_BIG: + b = tmp = sexp_make_ratio(ctx, b, SEXP_ONE); + case SEXP_NUM_FIX_RAT: + case SEXP_NUM_BIG_RAT: + if (!sexp_ratiop(a)) + a = tmp = sexp_make_ratio(ctx, a, SEXP_ONE); + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_RAT: + r = sexp_ratio_div(ctx, a, b); + break; +#endif } sexp_gc_release2(ctx); return r; @@ -667,7 +868,7 @@ sexp sexp_quotient (sexp ctx, sexp a, sexp b) { sexp r=SEXP_VOID; sexp_gc_var1(tmp); sexp_gc_preserve1(ctx, tmp); - switch ((at << 2) + bt) { + 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: r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); @@ -676,9 +877,16 @@ sexp sexp_quotient (sexp ctx, sexp a, sexp b) { 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: case SEXP_NUM_RAT_FIX: case SEXP_NUM_RAT_FLO: + case SEXP_NUM_RAT_BIG: case SEXP_NUM_RAT_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_FIX_RAT: case SEXP_NUM_BIG_RAT: +#endif r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); break; case SEXP_NUM_FIX_FIX: @@ -703,7 +911,7 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) { sexp r=SEXP_VOID; sexp_gc_var1(tmp); sexp_gc_preserve1(ctx, tmp); - switch ((at << 2) + bt) { + 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: r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); @@ -712,9 +920,16 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) { 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: case SEXP_NUM_RAT_FIX: case SEXP_NUM_RAT_FLO: + case SEXP_NUM_RAT_BIG: case SEXP_NUM_RAT_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_FIX_RAT: case SEXP_NUM_BIG_RAT: +#endif r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); break; case SEXP_NUM_FIX_FIX: @@ -738,11 +953,13 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) { int at=sexp_number_type(a), bt=sexp_number_type(b); sexp r=SEXP_VOID; double f; + sexp_gc_var1(tmp); + sexp_gc_preserve1(ctx, tmp); if (at > bt) { r = sexp_compare(ctx, b, a); sexp_negate(r); } else { - switch ((at << 2) + bt) { + 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: r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); @@ -768,8 +985,20 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) { case SEXP_NUM_BIG_BIG: r = sexp_make_fixnum(sexp_bignum_compare(a, b)); break; +#if SEXP_USE_RATIOS + case SEXP_NUM_FLO_RAT: + r = sexp_make_fixnum((sexp_sint_t)(sexp_flonum_value(a) - sexp_ratio_to_double(b))); + break; + case SEXP_NUM_FIX_RAT: + case SEXP_NUM_BIG_RAT: + a = tmp = sexp_make_ratio(ctx, a, SEXP_ONE); + /* ... FALLTHROUGH ... */ + case SEXP_NUM_RAT_RAT: + r = sexp_ratio_compare(ctx, a, b); + break; +#endif } } + sexp_gc_release1(ctx); return r; } - diff --git a/sexp.c b/sexp.c index 2a8f8a6f..c1209c01 100644 --- a/sexp.c +++ b/sexp.c @@ -97,6 +97,8 @@ static struct sexp_type_struct _sexp_type_specs[] = { {SEXP_VECTOR, sexp_offsetof(vector, data), 0, 0, sexp_offsetof(vector, length), 1, sexp_sizeof(vector), sexp_offsetof(vector, length), sizeof(sexp), 0, 0, 0, 0, 0, 0, "vector", SEXP_FALSE, SEXP_FALSE, NULL}, {SEXP_FLONUM, 0, 0, 0, 0, 0, sexp_sizeof(flonum), 0, 0, 0, 0, 0, 0, 0, 0, "real", SEXP_FALSE, SEXP_FALSE, NULL}, {SEXP_BIGNUM, 0, 0, 0, 0, 0, sexp_sizeof(bignum), sexp_offsetof(bignum, length), sizeof(sexp_uint_t), 0, 0, 0, 0, 0, 0, "bignum", SEXP_FALSE, SEXP_FALSE, NULL}, + {SEXP_RATIO, sexp_offsetof(ratio, numerator), 2, 2, 0, 0, sexp_sizeof(ratio), 0, 0, 0, 0, 0, 0, 0, 0, "ratio", SEXP_FALSE, SEXP_FALSE, NULL}, + {SEXP_COMPLEX, sexp_offsetof(complex, real), 2, 2, 0, 0, sexp_sizeof(complex), 0, 0, 0, 0, 0, 0, 0, 0, "complex", SEXP_FALSE, SEXP_FALSE, NULL}, {SEXP_IPORT, sexp_offsetof(port, name), 2, 2, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, "input-port", SEXP_FALSE, SEXP_FALSE, SEXP_FINALIZE_PORT}, {SEXP_OPORT, sexp_offsetof(port, name), 2, 2, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, "output-port", SEXP_FALSE, SEXP_FALSE, SEXP_FINALIZE_PORT}, {SEXP_EXCEPTION, sexp_offsetof(exception, kind), 6, 6, 0, 0, sexp_sizeof(exception), 0, 0, 0, 0, 0, 0, 0, 0, "exception", SEXP_FALSE, SEXP_FALSE, NULL}, @@ -1371,6 +1373,22 @@ sexp sexp_write_one (sexp ctx, sexp obj, sexp out) { case SEXP_BIGNUM: sexp_write_bignum(ctx, obj, out, 10); break; +#endif +#if SEXP_USE_RATIOS + case SEXP_RATIO: + sexp_write(ctx, sexp_ratio_numerator(obj), out); + sexp_write_char(ctx, '/', out); + sexp_write(ctx, sexp_ratio_denominator(obj), out); + break; +#endif +#if SEXP_USE_COMPLEX + case SEXP_COMPLEX: + sexp_write(ctx, sexp_complex_real(obj), out); + if (!sexp_negativep(sexp_complex_imag(obj))) + sexp_write_char(ctx, '+', out); + sexp_write(ctx, sexp_complex_imag(obj), out); + sexp_write_char(ctx, 'i', out); + break; #endif case SEXP_OPCODE: sexp_write_string(ctx, "#", out); break; default: - sexp_write_string(ctx, "#", out); + sexp_write_string(ctx, "#', out); } } return SEXP_VOID; @@ -1603,13 +1623,52 @@ sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) { #endif } +#if SEXP_USE_RATIOS +sexp sexp_make_ratio (sexp ctx, sexp num, sexp den) { + sexp res = sexp_alloc_type(ctx, ratio, SEXP_RATIO); + sexp_ratio_numerator(res) = num; + sexp_ratio_denominator(res) = den; + return res; +} + +sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in) { + sexp tmp; + sexp_gc_var2(num, den); + sexp_gc_preserve2(ctx, num, den); + num = sexp_ratio_numerator(rat), den = sexp_ratio_denominator(rat); + if (den == SEXP_ZERO) + return sexp_read_error(ctx, "zero denominator in ratio", rat, in); + else if (num == SEXP_ZERO) + return SEXP_ZERO; + while (den != SEXP_ZERO) { + tmp = sexp_remainder(ctx, num, den); + if (sexp_exceptionp(tmp)) { + sexp_gc_release2(ctx); + return tmp; + } + num = den, den = tmp; + } + sexp_ratio_denominator(rat) + = den = sexp_quotient(ctx, sexp_ratio_denominator(rat), num); + sexp_ratio_numerator(rat) + = sexp_quotient(ctx, sexp_ratio_numerator(rat), num); + if (sexp_exact_negativep(sexp_ratio_denominator(rat))) { + sexp_negate(sexp_ratio_numerator(rat)); + sexp_negate(sexp_ratio_denominator(rat)); + } + sexp_gc_release2(ctx); + return (sexp_ratio_denominator(rat) == SEXP_ONE) ? sexp_ratio_numerator(rat) + : rat; +} +#endif + sexp sexp_read_number (sexp ctx, sexp in, int base) { - sexp den; - sexp_uint_t res = 0, tmp; + sexp_sint_t val = 0, tmp; int c, digit, negativep = 0; #if SEXP_USE_PLACEHOLDER_DIGITS double whole = 0.0, scale = 0.1; #endif + sexp_gc_var2(res, den); c = sexp_read_char(ctx, in); if (c == '-') { @@ -1621,19 +1680,19 @@ sexp sexp_read_number (sexp ctx, sexp in, int base) { digit = digit_value(c); if ((digit < 0) || (digit >= base)) break; - tmp = res * base + digit; + tmp = val * base + digit; #if SEXP_USE_BIGNUMS - if ((tmp < res) || (tmp > SEXP_MAX_FIXNUM)) { + if ((tmp < val) || (tmp > SEXP_MAX_FIXNUM)) { sexp_push_char(ctx, c, in); - return sexp_read_bignum(ctx, in, res, (negativep ? -1 : 1), base); + return sexp_read_bignum(ctx, in, val, (negativep ? -1 : 1), base); } #endif - res = tmp; + val = tmp; } #if SEXP_USE_PLACEHOLDER_DIGITS if (sexp_placeholder_digit_p(c)) { - whole = res; + whole = val; for ( ; sexp_placeholder_digit_p(c); c=sexp_read_char(ctx, in)) whole = whole*10 + sexp_placeholder_digit_value(base); if ((c=='.' || c=='e' || c=='E') && (base != 10)) @@ -1658,14 +1717,22 @@ 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, res, negativep); + return sexp_read_float_tail(ctx, in, val, negativep); } else if (c=='/') { + sexp_gc_preserve2(ctx, res, den); den = sexp_read_number(ctx, in, base); - if (! sexp_fixnump(den)) + if (! (sexp_fixnump(den) || sexp_bignump(den))) return (sexp_exceptionp(den) ? den : sexp_read_error(ctx, "invalid rational syntax", den, in)); - return sexp_make_flonum(ctx, (double)(negativep ? -res : res) - / (double)sexp_unbox_fixnum(den)); +#if SEXP_USE_RATIOS + res = sexp_make_ratio(ctx, sexp_make_fixnum(negativep ? -val : val), den); + res = sexp_ratio_normalize(ctx, res, in); +#else + res = sexp_make_flonum(ctx, (double)(negativep ? -val : val) + / (double)sexp_unbox_fixnum(den)); +#endif + sexp_gc_release2(ctx); + return res; } else { if ((c!=EOF) && ! is_separator(c)) return sexp_read_error(ctx, "invalid numeric syntax", @@ -1673,7 +1740,7 @@ sexp sexp_read_number (sexp ctx, sexp in, int base) { sexp_push_char(ctx, c, in); } - return sexp_make_fixnum(negativep ? -res : res); + return sexp_make_fixnum(negativep ? -val : val); } #if SEXP_USE_UTF8_STRINGS @@ -1978,6 +2045,16 @@ sexp sexp_read_raw (sexp ctx, sexp in) { else sexp_bignum_sign(res) = -sexp_bignum_sign(res); } else +#endif +#if SEXP_USE_RATIOS + if (sexp_ratiop(res)) { + sexp_negate(sexp_ratio_numerator(res)); + } else +#endif +#if SEXP_USE_COMPLEX + if (sexp_complexp(res)) { + sexp_negate(sexp_complex_real(res)); + } else #endif res = sexp_fx_mul(res, SEXP_NEG_ONE); } diff --git a/vm.c b/vm.c index a8c1e083..79f40145 100644 --- a/vm.c +++ b/vm.c @@ -1620,6 +1620,10 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { #if SEXP_USE_BIGNUMS else if (sexp_bignump(_ARG1)) _ARG1 = sexp_make_flonum(ctx, sexp_bignum_to_double(_ARG1)); +#endif +#if SEXP_USE_RATIOS + else if (sexp_ratiop(_ARG1)) + _ARG1 = sexp_make_flonum(ctx, sexp_ratio_to_double(_ARG1)); #endif else if (! sexp_flonump(_ARG1)) sexp_raise("exact->inexact: not a number", sexp_list1(ctx, _ARG1));