klisp

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

commit 9b7e91e97554f09bfa016cc1bc39343b413ed4b3
parent 6a422ae614b1c784cbe8a6e3408d6c1a571c5f57
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Mon, 25 Apr 2011 18:03:33 -0300

Added floor, ceiling, truncate & round.

Diffstat:
Msrc/kgnumbers.c | 35++++++++++++++++++++++++++++++++++-
Msrc/kgnumbers.h | 3++-
Msrc/kground.c | 9++++++++-
Msrc/krational.c | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/krational.h | 8+++-----
5 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -426,6 +426,24 @@ TValue knum_denominator(klisp_State *K, TValue n) } } +/* GC: assumes n is rooted */ +TValue knum_real_to_integer(klisp_State *K, TValue n, kround_mode mode) +{ + switch(ttype(n)) { + case K_TFIXINT: + case K_TBIGINT: + return n; /* integers are easy */ + case K_TBIGRAT: + return kbigrat_to_integer(K, n, mode); + case K_TEINF: + klispE_throw(K, "round: infinite value"); + return KINERT; + default: + klispE_throw(K, "denominator: unsopported type"); + return KINERT; + } +} + /* 12.5.4 + */ void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) { @@ -1103,7 +1121,22 @@ void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.8.4 floor, ceiling, truncate, round */ -/* TODO */ +void kreal_to_integer(klisp_State *K, TValue *xparams, TValue ptree, + TValue denv) +{ + /* + ** xparams[0]: symbol name + ** xparams[1]: bool: true min, false max + */ + UNUSED(denv); + char *name = ksymbol_buf(xparams[0]); + kround_mode mode = (kround_mode) ivalue(xparams[1]); + + bind_1tp(K, name, ptree, "real", krealp, n); + + TValue res = knum_real_to_integer(K, n, mode); + kapply_cc(K, res); +} /* 12.8.5 rationalize, simplest-rational */ /* TODO */ diff --git a/src/kgnumbers.h b/src/kgnumbers.h @@ -122,7 +122,8 @@ 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 */ +void kreal_to_integer(klisp_State *K, TValue *xparams, TValue ptree, + TValue denv); /* 12.8.5 rationalize, simplest-rational */ /* TODO */ diff --git a/src/kground.c b/src/kground.c @@ -747,7 +747,14 @@ void kinit_ground_env(klisp_State *K) add_applicative(K, ground_env, "denominator", kdenominator, 0); /* 12.8.4 floor, ceiling, truncate, round */ - /* TODO */ + add_applicative(K, ground_env, "floor", kreal_to_integer, 2, + symbol, i2tv((int32_t) K_FLOOR)); + add_applicative(K, ground_env, "ceiling", kreal_to_integer, 2, + symbol, i2tv((int32_t) K_CEILING)); + add_applicative(K, ground_env, "truncate", kreal_to_integer, 2, + symbol, i2tv((int32_t) K_TRUNCATE)); + add_applicative(K, ground_env, "round", kreal_to_integer, 2, + symbol, i2tv((int32_t) K_ROUND_EVEN)); /* 12.8.5 rationalize, simplest-rational */ /* TODO */ diff --git a/src/krational.c b/src/krational.c @@ -257,3 +257,46 @@ TValue kbigrat_denominator(klisp_State *K, TValue tv_bigrat) return kbigint_try_fixint(K, copy); } } + +TValue kbigrat_to_integer(klisp_State *K, TValue tv_bigrat, kround_mode mode) +{ + /* do an usigned divide first */ + TValue tv_quot = kbigint_make_simple(K); + krooted_tvs_push(K, tv_quot); + TValue tv_rest = kbigint_make_simple(K); + krooted_tvs_push(K, tv_rest); + Bigint *quot = tv2bigint(tv_quot); + Bigint *rest = tv2bigint(tv_rest); + Bigrat *n = tv2bigrat(tv_bigrat); + + UNUSED(mp_int_abs(K, MP_NUMER_P(n), quot)); + UNUSED(mp_int_div(K, quot, MP_DENOM_P(n), quot, rest)); + + if (mp_rat_compare_zero(n) < 0) + UNUSED(mp_int_neg(K, quot, quot)); + + switch(mode) { + case K_TRUNCATE: + /* nothing needs to be done */ + break; + case K_CEILING: + if (mp_rat_compare_zero(n) > 0 && mp_int_compare_zero(rest) != 0) + UNUSED(mp_int_add_value(K, quot, 1, quot)); + break; + case K_FLOOR: + if (mp_rat_compare_zero(n) < 0 && mp_int_compare_zero(rest) != 0) + UNUSED(mp_int_sub_value(K, quot, 1, quot)); + break; + case K_ROUND_EVEN: + UNUSED(mp_int_mul_pow2(K, rest, 1, rest)); + if (mp_int_compare(rest, MP_DENOM_P(n)) == 0 && + mp_int_is_odd(quot)) + UNUSED(mp_int_add_value(K, quot, mp_rat_compare_zero(n) < 0? + -1 : 1, quot)); + break; + } + + krooted_tvs_pop(K); + krooted_tvs_pop(K); + return kbigint_try_fixint(K, tv_quot); +} diff --git a/src/krational.h b/src/krational.h @@ -167,12 +167,10 @@ TValue kbigrat_numerator(klisp_State *K, TValue tv_bigrat); TValue kbigrat_denominator(klisp_State *K, TValue tv_bigrat); /* TODO implement these */ -#if 0 -TValue kbigrat_floor(klisp_State *K, TValue n1, TValue n2); -TValue kbigrat_ceiling(klisp_State *K, TValue n1, TValue n2); -TValue kbigrat_truncate(klisp_State *K, TValue n1, TValue n2); -TValue kbigrat_round(klisp_State *K, TValue n1, TValue n2); +typedef enum { K_FLOOR, K_CEILING, K_TRUNCATE, K_ROUND_EVEN } kround_mode; +TValue kbigrat_to_integer(klisp_State *K, TValue tv_bigrat, kround_mode mode); +#if 0 TValue kbigrat_simplest_rational(klisp_State *K, TValue n1, TValue n2); TValue kbigrat_rationalize(klisp_State *K, TValue n1, TValue n2); #endif