klisp

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

commit 21c9adcd718703fbb6a12c6798d21910ba316ca2
parent b3ad5ba049fd99f9f193d9d0082271536eb61fb4
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Wed,  4 May 2011 21:12:51 -0300

Added double_to_exact.

Diffstat:
Msrc/Makefile | 2+-
Msrc/kreal.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kreal.h | 3+++
3 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/src/Makefile b/src/Makefile @@ -51,7 +51,7 @@ kinteger.o: kinteger.c kinteger.h kobject.h kstate.h kmem.h klisp.h imath.h \ krational.o: krational.c krational.h kinteger.h kobject.h kstate.h kmem.h \ klisp.h imrat.h kgc.h kreal.o: kreal.c kreal.h krational.h kinteger.h kobject.h kstate.h kmem.h \ - klisp.h imrat.h kgc.h + klisp.h imrat.h kgc.h kerror.h kpair.h kpair.o: kpair.c kpair.h kobject.h kstate.h kmem.h klisp.h kgc.h kstring.o: kstring.c kstring.h kobject.h kstate.h kmem.h klisp.h kgc.h ksymbol.o: ksymbol.c ksymbol.h kobject.h kstring.h kstate.h kmem.h \ diff --git a/src/kreal.c b/src/kreal.c @@ -18,6 +18,8 @@ #include "kstate.h" #include "kmem.h" #include "kgc.h" +#include "kpair.h" /* for list in throw error */ +#include "kerror.h" /* MAYBE move to kobject.h */ #define ktag_double(d_) \ @@ -127,6 +129,139 @@ TValue kexact_to_inexact(klisp_State *K, TValue n) } } +/* assume d is integer and doesn't fit in a fixint */ +TValue kdouble_to_bigint(klisp_State *K, double d) +{ + bool neg = d < 0; + if (neg) + d = -d; + + TValue tv_res = kbigint_make_simple(K); + krooted_tvs_push(K, tv_res); + Bigint *res = tv2bigint(tv_res); + mp_int_set_value(K, res, 0); + + TValue tv_digit = kbigint_make_simple(K); + krooted_tvs_push(K, tv_digit); + Bigint *digit = tv2bigint(tv_digit); + + /* do it 32 bits at a time */ + double radix = ((double) UINT32_MAX) + 1.0; + int power = 0; + while(d > 0) { + double dd = fmod(d, radix); + d = floor(d / radix); + /* load in two moves because set_value takes signed ints */ + uint32_t id = (uint32_t) dd; + int32_t id1 = (int32_t) (id >> 1); + int32_t id2 = (int32_t) (id - id1); + + mp_int_set_value(K, digit, id1); + mp_int_add_value(K, digit, id2, digit); + + mp_int_mul_pow2(K, digit, power, digit); + mp_int_add(K, res, digit, res); + + power += 32; + } + + if (neg) + mp_int_neg(K, res, res); + + krooted_tvs_pop(K); /* digit */ + krooted_tvs_pop(K); /* res */ + + return tv_res; /* can't be fixint except when coming from + kdouble_to_bigrat, so don't convert */ +} + +/* TODO: should do something like rationalize with range +/- 1/2ulp) */ +TValue kdouble_to_bigrat(klisp_State *K, double d) +{ + bool neg = d < 0; + if (neg) + d = -d; + + /* find an integer, convert it and divide by + an adequate power of 2 */ + TValue tv_res = kbigrat_make_simple(K); + krooted_tvs_push(K, tv_res); + Bigrat *res = tv2bigrat(tv_res); + UNUSED(mp_rat_set_value(K, res, 0, 1)); + + TValue tv_den = kbigint_make_simple(K); + krooted_tvs_push(K, tv_den); + Bigint *den = tv2bigint(tv_den); + UNUSED(mp_int_set_value(K, den, 1)); + + /* XXX could be made a lot more efficiently */ + int32_t power = 16; + double radix = pow(2, power); + while(d != floor(d)) { + d *= radix; + UNUSED(mp_int_mul_pow2(K, den, power, den)); + } + + TValue tv_num = kdouble_to_bigint(K, d); + krooted_tvs_push(K, tv_num); + Bigint *num = tv2bigint(tv_num); + + TValue tv_den2 = kbigrat_make_simple(K); + krooted_tvs_push(K, tv_den2); + Bigrat *den2 = tv2bigrat(tv_den2); + + UNUSED(mp_rat_set_value(K, den2, 0, 1)); + UNUSED(mp_rat_add_int(K, den2, den, den2)); + UNUSED(mp_rat_set_value(K, res, 0, 1)); + UNUSED(mp_rat_add_int(K, res, num, res)); + UNUSED(mp_rat_div(K, res, den2, res)); + + if (neg) + mp_rat_neg(K, res, res); + + krooted_tvs_pop(K); /* den2 */ + krooted_tvs_pop(K); /* num */ + krooted_tvs_pop(K); /* den */ + krooted_tvs_pop(K); /* res */ + + return tv_res; /* can't be integer */ +} + +TValue kinexact_to_exact(klisp_State *K, TValue n) +{ + switch(ttype(n)) { + case K_TFIXINT: + case K_TBIGINT: + case K_TBIGRAT: + case K_TEINF: + /* all of these are already exact */ + return n; + case K_TDOUBLE: { + double d = dvalue(n); + klisp_assert(!isnan(d) && !isinf(d)); + if (d == floor(d)) { /* integer */ + if (d <= (double) INT32_MAX && + d >= (double) INT32_MIN) { + return i2tv((int32_t) d); /* fixint */ + } else { + return kdouble_to_bigint(K, d); + } + } else { /* non integer rational */ + return kdouble_to_bigrat(K, d); + } + } + case K_TIINF: + return tv_equal(n, KIPINF)? KEPINF : KEMINF; + case K_TRWNPV: + case K_TUNDEFINED: + klispE_throw_simple_with_irritants(K, "no primary value", 1, n); + return KUNDEF; + default: + klisp_assert(0); + return KUNDEF; + } +} + /* ** read/write interface */ diff --git a/src/kreal.h b/src/kreal.h @@ -16,7 +16,10 @@ #include "kinteger.h" #include "imrat.h" +/* REFACTOR rename. These can take any real, but + kreal_to_... is taken by kgnumbers... */ TValue kexact_to_inexact(klisp_State *K, TValue n); +TValue kinexact_to_exact(klisp_State *K, TValue n); /*