klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 6a422ae614b1c784cbe8a6e3408d6c1a571c5f57
parent 2fef85618d6017a883269993b109f4840f42b34f
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sun, 24 Apr 2011 09:45:40 -0300

Added numerator and denominator to the ground environment.

Diffstat:
Msrc/kgnumbers.c | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/kgnumbers.h | 3++-
Msrc/kground.c | 11+++++++++--
Msrc/kinteger.c | 47++++++++++++++---------------------------------
Msrc/kinteger.h | 32++++++++++++++++++++++++++------
Msrc/krational.c | 63+++++++++++++++++++++++++++++++++++----------------------------
Msrc/krational.h | 32+++++++++++++++++++++++++++++---
7 files changed, 177 insertions(+), 74 deletions(-)

diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -394,6 +394,38 @@ TValue knum_lcm(klisp_State *K, TValue n1, TValue n2) } } +/* GC: assumes n is rooted */ +TValue knum_numerator(klisp_State *K, TValue n) +{ + switch(ttype(n)) { + case K_TFIXINT: + case K_TBIGINT: + return n; + case K_TBIGRAT: + return kbigrat_numerator(K, n); +/* case K_TEINF: infinities are not rational! */ + default: + klispE_throw(K, "numerator: unsopported type"); + return KINERT; + } +} + +/* GC: assumes n is rooted */ +TValue knum_denominator(klisp_State *K, TValue n) +{ + switch(ttype(n)) { + case K_TFIXINT: + case K_TBIGINT: + return i2tv(1); /* denominator of integer is always (+)1 */ + case K_TBIGRAT: + return kbigrat_denominator(K, n); +/* case K_TEINF: infinities are not rational! */ + default: + klispE_throw(K, "denominator: unsopported type"); + return KINERT; + } +} + /* 12.5.4 + */ void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) { @@ -682,7 +714,7 @@ void kdiv_mod(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) UNUSED(denv); - bind_2tp(K, name, ptree, "number", krealp, tv_n, + bind_2tp(K, name, ptree, "real", krealp, tv_n, "number", krealp, tv_d); TValue tv_div, tv_mod; @@ -1046,3 +1078,32 @@ void kdivided(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } + +/* 12.8.3 numerator, denominator */ +void knumerator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +{ + UNUSED(denv); + UNUSED(xparams); + + bind_1tp(K, "numerator", ptree, "rational", krationalp, n); + + TValue res = knum_numerator(K, n); + kapply_cc(K, res); +} + +void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +{ + UNUSED(denv); + UNUSED(xparams); + + bind_1tp(K, "denominator", ptree, "rational", krationalp, n); + + TValue res = knum_denominator(K, n); + kapply_cc(K, res); +} + +/* 12.8.4 floor, ceiling, truncate, round */ +/* TODO */ + +/* 12.8.5 rationalize, simplest-rational */ +/* TODO */ diff --git a/src/kgnumbers.h b/src/kgnumbers.h @@ -118,7 +118,8 @@ void klcm(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); void kdivided(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); /* 12.8.3 numerator, denominator */ -/* TODO */ +void knumerator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); /* 12.8.4 floor, ceiling, truncate, round */ /* TODO */ diff --git a/src/kground.c b/src/kground.c @@ -735,15 +735,22 @@ void kinit_ground_env(klisp_State *K) ** 12.8 Rational features */ - /* 12.8.1 rational */ + /* 12.8.1 rational? */ add_applicative(K, ground_env, "rational?", ftypep, 2, symbol, p2tv(krationalp)); /* 12.8.2 / */ add_applicative(K, ground_env, "/", kdivided, 0); + /* 12.8.3 numerator, denominator */ + add_applicative(K, ground_env, "numerator", knumerator, 0); + add_applicative(K, ground_env, "denominator", kdenominator, 0); + + /* 12.8.4 floor, ceiling, truncate, round */ + /* TODO */ + + /* 12.8.5 rationalize, simplest-rational */ /* TODO */ - /* complete module rational */ /* ** diff --git a/src/kinteger.c b/src/kinteger.c @@ -15,25 +15,6 @@ #include "kmem.h" #include "kgc.h" -/* This tries to convert a bigint to a fixint */ -/* XXX this doesn't need K really */ -inline TValue kbigint_try_fixint(klisp_State *K, TValue n) -{ - UNUSED(K); - Bigint *b = tv2bigint(n); - if (MP_USED(b) != 1) - return n; - - int64_t digit = (int64_t) *(MP_DIGITS(b)); - if (MP_SIGN(b) == MP_NEG) digit = -digit; - if (kfit_int32_t(digit)) { - /* n shouln't be reachable but the let the gc do its job */ - return i2tv((int32_t) digit); - } else { - return n; - } -} - /* It is used for reading and for creating temps and res in all operations */ /* NOTE: is uint to allow INT32_MIN as positive argument in read */ TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit) @@ -60,7 +41,7 @@ TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit) /* assumes src is rooted */ TValue kbigint_copy(klisp_State *K, TValue src) { - TValue copy = kbigint_new(K, false, 0); + TValue copy = kbigint_make_simple(K); /* arguments are in reverse order with respect to mp_int_copy */ UNUSED(mp_int_init_copy(K, tv2bigint(copy), tv2bigint(src))); return copy; @@ -74,7 +55,7 @@ TValue kbigint_copy(klisp_State *K, TValue src) bool kinteger_read(klisp_State *K, char *buf, int32_t base, TValue *out, char **end) { - TValue res = kbigint_new(K, false, 0); + TValue res = kbigint_make_simple(K); krooted_tvs_push(K, res); bool ret_val = (mp_int_read_cstring(K, tv2bigint(res), base, buf, end) == MP_OK); @@ -136,7 +117,7 @@ bool kbigint_gep(TValue tv_bigint1, TValue tv_bigint2) */ TValue kbigint_plus(klisp_State *K, TValue n1, TValue n2) { - TValue res = kbigint_new(K, false, 0); + TValue res = kbigint_make_simple(K); krooted_tvs_push(K, res); UNUSED(mp_int_add(K, tv2bigint(n1), tv2bigint(n2), tv2bigint(res))); krooted_tvs_pop(K); @@ -145,7 +126,7 @@ TValue kbigint_plus(klisp_State *K, TValue n1, TValue n2) TValue kbigint_times(klisp_State *K, TValue n1, TValue n2) { - TValue res = kbigint_new(K, false, 0); + TValue res = kbigint_make_simple(K); krooted_tvs_push(K, res); UNUSED(mp_int_mul(K, tv2bigint(n1), tv2bigint(n2), tv2bigint(res))); krooted_tvs_pop(K); @@ -154,7 +135,7 @@ TValue kbigint_times(klisp_State *K, TValue n1, TValue n2) TValue kbigint_minus(klisp_State *K, TValue n1, TValue n2) { - TValue res = kbigint_new(K, false, 0); + TValue res = kbigint_make_simple(K); krooted_tvs_push(K, res); UNUSED(mp_int_sub(K, tv2bigint(n1), tv2bigint(n2), tv2bigint(res))); krooted_tvs_pop(K); @@ -164,9 +145,9 @@ TValue kbigint_minus(klisp_State *K, TValue n1, TValue n2) /* NOTE: n2 can't be zero, that case should be checked before calling this */ TValue kbigint_div_mod(klisp_State *K, TValue n1, TValue n2, TValue *res_r) { - TValue tv_q = kbigint_new(K, false, 0); + TValue tv_q = kbigint_make_simple(K); krooted_tvs_push(K, tv_q); - TValue tv_r = kbigint_new(K, false, 0); + TValue tv_r = kbigint_make_simple(K); krooted_tvs_push(K, tv_r); Bigint *n = tv2bigint(n1); @@ -198,9 +179,9 @@ TValue kbigint_div_mod(klisp_State *K, TValue n1, TValue n2, TValue *res_r) TValue kbigint_div0_mod0(klisp_State *K, TValue n1, TValue n2, TValue *res_r) { /* GC: root bigints */ - TValue tv_q = kbigint_new(K, false, 0); + TValue tv_q = kbigint_make_simple(K); krooted_tvs_push(K, tv_q); - TValue tv_r = kbigint_new(K, false, 0); + TValue tv_r = kbigint_make_simple(K); krooted_tvs_push(K, tv_r); Bigint *n = tv2bigint(n1); @@ -212,12 +193,12 @@ TValue kbigint_div0_mod0(klisp_State *K, TValue n1, TValue n2, TValue *res_r) /* Adjust q & r so that -|d/2| <= r < |d/2| */ /* It seems easier to check -|d| <= 2r < |d| */ - TValue tv_two_r = kbigint_new(K, false, 0); + TValue tv_two_r = kbigint_make_simple(K); krooted_tvs_push(K, tv_two_r); Bigint *two_r = tv2bigint(tv_two_r); /* two_r = r * 2 = r * 2^1 */ UNUSED(mp_int_mul_pow2(K, r, 1, two_r)); - TValue tv_abs_d = kbigint_new(K, false, 0); + TValue tv_abs_d = kbigint_make_simple(K); krooted_tvs_push(K, tv_abs_d); /* NOTE: this makes a copy if d >= 0 */ Bigint *abs_d = tv2bigint(tv_abs_d); @@ -280,7 +261,7 @@ bool kbigint_evenp(TValue tv_bigint) TValue kbigint_abs(klisp_State *K, TValue tv_bigint) { if (kbigint_negativep(tv_bigint)) { - TValue copy = kbigint_new(K, false, 0); + TValue copy = kbigint_make_simple(K); krooted_tvs_push(K, copy); UNUSED(mp_int_abs(K, tv2bigint(tv_bigint), tv2bigint(copy))); krooted_tvs_pop(K); @@ -293,7 +274,7 @@ TValue kbigint_abs(klisp_State *K, TValue tv_bigint) TValue kbigint_gcd(klisp_State *K, TValue n1, TValue n2) { - TValue res = kbigint_new(K, false, 0); + TValue res = kbigint_make_simple(K); krooted_tvs_push(K, res); UNUSED(mp_int_gcd(K, tv2bigint(n1), tv2bigint(n2), tv2bigint(res))); krooted_tvs_pop(K); @@ -302,7 +283,7 @@ TValue kbigint_gcd(klisp_State *K, TValue n1, TValue n2) TValue kbigint_lcm(klisp_State *K, TValue n1, TValue n2) { - TValue tv_res = kbigint_new(K, false, 0); + TValue tv_res = kbigint_make_simple(K); krooted_tvs_push(K, tv_res); Bigint *res = tv2bigint(tv_res); /* unlike in kernel, lcm in IMath can return a negative value diff --git a/src/kinteger.h b/src/kinteger.h @@ -15,17 +15,37 @@ #include "kstate.h" #include "imath.h" -/* for now used only for reading */ +/* Check to see if an int64_t fits in a int32_t */ +inline bool kfit_int32_t(int64_t n) { + return (n >= (int64_t) INT32_MIN && n <= (int64_t) INT32_MAX); +} + +/* This tries to convert a bigint to a fixint */ +/* XXX this doesn't need K really */ +inline TValue kbigint_try_fixint(klisp_State *K, TValue n) +{ + UNUSED(K); + Bigint *b = tv2bigint(n); + if (MP_USED(b) != 1) + return n; + + int64_t digit = (int64_t) *(MP_DIGITS(b)); + if (MP_SIGN(b) == MP_NEG) digit = -digit; + if (kfit_int32_t(digit)) { + /* n shouln't be reachable but the let the gc do its job */ + return i2tv((int32_t) digit); + } else { + return n; + } +} + /* NOTE: is uint and has flag to allow INT32_MIN as positive argument */ TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit); -/* used in write to destructively get the digits & in bigrat */ TValue kbigint_copy(klisp_State *K, TValue src); -/* Check to see if an int64_t fits in a int32_t */ -inline bool kfit_int32_t(int64_t n) { - return (n >= (int64_t) INT32_MIN && n <= (int64_t) INT32_MAX); -} +/* macro to create the simplest bigint */ +#define kbigint_make_simple(K_) kbigint_new(K_, false, 0) /* Create a stack allocated bigints from a fixint, useful for mixed operations, relatively light weight compared diff --git a/src/krational.c b/src/krational.c @@ -17,31 +17,6 @@ #include "kmem.h" #include "kgc.h" -/* This tries to convert a bigrat to a fixint or a bigint */ -inline TValue kbigrat_try_integer(klisp_State *K, TValue n) -{ - Bigrat *b = tv2bigrat(n); - - if (!mp_rat_is_integer(b)) - return n; - - /* sadly we have to repeat the code from try_fixint here... */ - Bigint *i = MP_NUMER_P(b); - if (MP_USED(i) == 1) { - int64_t digit = (int64_t) *(MP_DIGITS(i)); - if (MP_SIGN(i) == MP_NEG) digit = -digit; - if (kfit_int32_t(digit)) - return i2tv((int32_t) digit); - /* else fall through */ - } - /* should alloc a bigint */ - /* GC: n may not be rooted */ - krooted_tvs_push(K, n); - TValue copy = kbigint_copy(K, gc2bigint(i)); - krooted_tvs_pop(K); - return copy; -} - /* used for res & temps in operations */ /* NOTE: This is to be called only with already reduced values */ TValue kbigrat_new(klisp_State *K, bool sign, uint32_t num, @@ -71,9 +46,6 @@ TValue kbigrat_new(klisp_State *K, bool sign, uint32_t num, return gc2bigrat(new_bigrat); } -/* macro to create the simplest rational */ -#define kbigrat_make_simple(K_) kbigrat_new(K_, false, 0, 1) - /* assumes src is rooted */ TValue kbigrat_copy(klisp_State *K, TValue src) { @@ -236,6 +208,7 @@ bool kbigrat_positivep(TValue tv_bigrat) return (mp_rat_compare_zero(tv2bigrat(tv_bigrat)) > 0); } +/* GC: These assume tv_bigrat is rooted */ /* needs the state to create a copy if negative */ TValue kbigrat_abs(klisp_State *K, TValue tv_bigrat) { @@ -250,3 +223,37 @@ TValue kbigrat_abs(klisp_State *K, TValue tv_bigrat) return tv_bigrat; } } + +TValue kbigrat_numerator(klisp_State *K, TValue tv_bigrat) +{ + int32_t fnum = 0; + Bigrat *bigrat = tv2bigrat(tv_bigrat); + if (mp_rat_to_ints(bigrat, &fnum, NULL) == MP_OK) + return i2tv(fnum); + else { + TValue copy = kbigint_make_simple(K); + krooted_tvs_push(K, copy); + UNUSED(mp_rat_numer(K, bigrat, tv2bigint(copy))); + krooted_tvs_pop(K); + /* NOTE: may still be a fixint because mp_rat_to_ints fails if + either numer or denom isn't a fixint */ + return kbigint_try_fixint(K, copy); + } +} + +TValue kbigrat_denominator(klisp_State *K, TValue tv_bigrat) +{ + int32_t fden = 0; + Bigrat *bigrat = tv2bigrat(tv_bigrat); + if (mp_rat_to_ints(bigrat, NULL, &fden) == MP_OK) + return i2tv(fden); + else { + TValue copy = kbigint_make_simple(K); + krooted_tvs_push(K, copy); + UNUSED(mp_rat_denom(K, bigrat, tv2bigint(copy))); + krooted_tvs_pop(K); + /* NOTE: may still be a fixint because mp_rat_to_ints fails if + either numer or denom isn't a fixint */ + return kbigint_try_fixint(K, copy); + } +} diff --git a/src/krational.h b/src/krational.h @@ -18,7 +18,30 @@ /* TEMP: for now we only implement bigrats (memory allocated) */ -/* TEMP: we'll see about reading & writing... */ +/* This tries to convert a bigrat to a fixint or a bigint */ +inline TValue kbigrat_try_integer(klisp_State *K, TValue n) +{ + Bigrat *b = tv2bigrat(n); + + if (!mp_rat_is_integer(b)) + return n; + + /* sadly we have to repeat the code from try_fixint here... */ + Bigint *i = MP_NUMER_P(b); + if (MP_USED(i) == 1) { + int64_t digit = (int64_t) *(MP_DIGITS(i)); + if (MP_SIGN(i) == MP_NEG) digit = -digit; + if (kfit_int32_t(digit)) + return i2tv((int32_t) digit); + /* else fall through */ + } + /* should alloc a bigint */ + /* GC: n may not be rooted */ + krooted_tvs_push(K, n); + TValue copy = kbigint_copy(K, gc2bigint(i)); + krooted_tvs_pop(K); + return copy; +} /* used in reading and for res & temps in operations */ TValue kbigrat_new(klisp_State *K, bool sign, uint32_t num, @@ -27,6 +50,9 @@ TValue kbigrat_new(klisp_State *K, bool sign, uint32_t num, /* used in write to destructively get the digits */ TValue kbigrat_copy(klisp_State *K, TValue src); +/* macro to create the simplest rational */ +#define kbigrat_make_simple(K_) kbigrat_new(K_, false, 0, 1) + /* Create a stack allocated bigrat from a bigint, useful for mixed operations, relatively light weight compared to creating it in the heap and burdening the gc */ @@ -137,8 +163,8 @@ bool kbigrat_positivep(TValue tv_bigrat); /* needs the state to create a copy if negative */ TValue kbigrat_abs(klisp_State *K, TValue tv_bigrat); -bool kbigrat_numerator(TValue tv_bigrat); -bool kbigrat_denominator(TValue tv_bigrat); +TValue kbigrat_numerator(klisp_State *K, TValue tv_bigrat); +TValue kbigrat_denominator(klisp_State *K, TValue tv_bigrat); /* TODO implement these */ #if 0