klisp

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

commit 51b19792042a7cc65292698f0a4c947f426ffcc6
parent 4ef1dabaea247b73f87767e529e87b5bb865b5b7
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sun,  1 May 2011 01:23:21 -0300

Added rational->real conversion.

Diffstat:
Msrc/kreal.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 55 insertions(+), 4 deletions(-)

diff --git a/src/kreal.c b/src/kreal.c @@ -28,8 +28,6 @@ else res = d2tv(d__); \ res;}) - - double kbigint_to_double(Bigint *bigint) { double radix = (double) UINT32_MAX + 1.0; @@ -45,6 +43,58 @@ double kbigint_to_double(Bigint *bigint) return mp_int_compare_zero(bigint) < 0? -accum : accum; } +/* bigrat is rooted */ +double kbigrat_to_double(klisp_State *K, Bigrat *bigrat) +{ + TValue tv_rem = kbigrat_copy(K, gc2bigrat(bigrat)); + krooted_tvs_push(K, tv_rem); + Bigrat *rem = tv2bigrat(tv_rem); + UNUSED(mp_rat_abs(K, rem, rem)); + + TValue int_radix = kbigint_make_simple(K); + krooted_tvs_push(K, int_radix); + /* cant do UINT32_MAX and then +1 because _value functions take + int32_t arguments */ + UNUSED(mp_int_set_value(K, tv2bigint(int_radix), INT32_MAX)); + UNUSED(mp_int_add_value(K, tv2bigint(int_radix), 1, + tv2bigint(int_radix))); + UNUSED(mp_int_add(K, tv2bigint(int_radix), tv2bigint(int_radix), + tv2bigint(int_radix))); + + TValue int_part = kbigint_make_simple(K); + krooted_tvs_push(K, int_part); + + double accum = 0.0; + double radix = (double) UINT32_MAX + 1.0; + uint32_t digit = 0; + /* inside there is a check to avoid problem with continuing fractions */ + while(mp_rat_compare_zero(rem) > 0) { + UNUSED(mp_int_div(K, MP_NUMER_P(rem), MP_DENOM_P(rem), + tv2bigint(int_part), NULL)); + + double di = kbigint_to_double(tv2bigint(int_part)); + bool was_zero = di == 0.0; + for (uint32_t i = 0; i < digit; i++) { + di /= radix; + } + /* if last di became 0.0 we will exit next loop, + this is to avoid problem with continuing fractions */ + if (!was_zero && di == 0.0) + break; + + ++digit; + accum += di; + + UNUSED(mp_rat_sub_int(K, rem, tv2bigint(int_part), rem)); + UNUSED(mp_rat_mul_int(K, rem, tv2bigint(int_radix), rem)); + } + krooted_tvs_pop(K); /* int_part */ + krooted_tvs_pop(K); /* int_radix */ + krooted_tvs_pop(K); /* rem */ + + return mp_rat_compare_zero(bigrat) < 0? -accum : accum; +} + TValue kexact_to_inexact(klisp_State *K, TValue n) { switch(ttype(n)) { @@ -58,8 +108,9 @@ TValue kexact_to_inexact(klisp_State *K, TValue n) return ktag_double(d); } case K_TBIGRAT: { - klisp_assert(0); - return KUNDEF; + Bigrat *bigrat = tv2bigrat(n); + double d = kbigrat_to_double(K, bigrat); + return ktag_double(d); } case K_TEINF: return tv_equal(n, KEPINF)? KIPINF : KIMINF;