diff options
| author | Keith Packard <keithp@keithp.com> | 2017-12-02 23:19:44 -0600 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2017-12-02 23:19:44 -0600 | 
| commit | 577911241db454bc3129fc47566c6a55752c4182 (patch) | |
| tree | 32c844fef65d307f472efb9d8a93ea68fa568a68 /src | |
| parent | b986a12b478a6d4ff550786d24aa8628dc0abe32 (diff) | |
altos/lisp: Overflow int computations to float
When an int computation overflows, switch to float.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/lisp/ao_lisp.h | 2 | ||||
| -rw-r--r-- | src/lisp/ao_lisp_builtin.c | 42 | 
2 files changed, 18 insertions, 26 deletions
| diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 1f3fb2b4..7cd8b5a5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -208,6 +208,8 @@ ao_lisp_bigint_int(uint32_t bi) {  #define AO_LISP_MIN_INT		(-(1 << (15 - AO_LISP_TYPE_SHIFT)))  #define AO_LISP_MAX_INT		((1 << (15 - AO_LISP_TYPE_SHIFT)) - 1) +#define AO_LISP_MIN_BIGINT	(-(1 << 24)) +#define AO_LISP_MAX_BIGINT	((1 << 24) - 1)  #define AO_LISP_NOT_INTEGER	0x7fffffff diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index d4751ac2..ad8f4125 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -321,24 +321,30 @@ ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)  		} else if (ao_lisp_integer_typep(rt) && ao_lisp_integer_typep(ct)) {  			int32_t	r = ao_lisp_poly_integer(ret);  			int32_t	c = ao_lisp_poly_integer(car); +			int64_t t;  			switch(op) {  			case builtin_plus:  				r += c; +			check_overflow: +				if (r < AO_LISP_MIN_BIGINT || AO_LISP_MAX_BIGINT < r) +					goto inexact;  				break;  			case builtin_minus:  				r -= c; +				goto check_overflow;  				break;  			case builtin_times: -				r *= c; +				t = (int64_t) r * (int64_t) c; +				if (t < AO_LISP_MIN_BIGINT || AO_LISP_MAX_BIGINT < t) +					goto inexact; +				r = (int32_t) t;  				break;  			case builtin_divide:  				if (c != 0 && (r % c) == 0)  					r /= c; -				else { -					ret = ao_lisp_float_get((float) r / (float) c); -					continue; -				} +				else +					goto inexact;  				break;  			case builtin_quotient:  				if (c == 0) @@ -365,8 +371,10 @@ ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)  			}  			ret = ao_lisp_integer_poly(r);  		} else if (ao_lisp_number_typep(rt) && ao_lisp_number_typep(ct)) { -			float r = ao_lisp_poly_number(ret); -			float c = ao_lisp_poly_number(car); +			float r, c; +		inexact: +			r = ao_lisp_poly_number(ret); +			c = ao_lisp_poly_number(car);  			switch(op) {  			case builtin_plus:  				r += c; @@ -380,28 +388,10 @@ ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)  			case builtin_divide:  				r /= c;  				break; -#if 0  			case builtin_quotient: -				if (c == 0) -					return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero"); -				if (r % c != 0 && (c < 0) != (r < 0)) -					r = r / c - 1; -				else -					r = r / c; -				break;  			case builtin_remainder: -				if (c == 0) -					return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero"); -				r %= c; -				break;  			case builtin_modulo: -				if (c == 0) -					return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero"); -				r %= c; -				if ((r < 0) != (c < 0)) -					r += c; -				break; -#endif +				return ao_lisp_error(AO_LISP_INVALID, "non-integer value in integer divide");  			default:  				break;  			} | 
