klisp

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

commit bf840103262c57f0cf81fe4fcf641fb67f43bc48
parent 1d3cc6969b0644dccf778fb7f44eedcc914d9b63
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sun, 10 Apr 2011 21:55:04 -0300

Added support for bigints to <?, <=?, >? & >=? applicatives.

Diffstat:
Msrc/kgnumbers.c | 22++++++++++++++++++++++
Msrc/kinteger.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kinteger.h | 27++++++++++++++++++++++-----
3 files changed, 113 insertions(+), 5 deletions(-)

diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -84,11 +84,18 @@ bool knum_eqp(TValue n1, TValue n2) } } +/* REFACTOR: could be just ltp and all other as calls to it + cf: kbigint_ltp, ... */ bool knum_ltp(TValue n1, TValue n2) { switch(max_ttype(n1, n2)) { case K_TFIXINT: return ivalue(n1) < ivalue(n2); + case K_TBIGINT: { + kensure_bigint(n1); + kensure_bigint(n2); + return kbigint_ltp(n1, n2); + } case K_TEINF: return !tv_equal(n1, n2) && (tv_equal(n1, KEMINF) || tv_equal(n2, KEPINF)); @@ -104,6 +111,11 @@ bool knum_lep(TValue n1, TValue n2) switch(max_ttype(n1, n2)) { case K_TFIXINT: return ivalue(n1) <= ivalue(n2); + case K_TBIGINT: { + kensure_bigint(n1); + kensure_bigint(n2); + return kbigint_lep(n1, n2); + } case K_TEINF: return tv_equal(n1, n2) || tv_equal(n1, KEMINF) || tv_equal(n2, KEPINF); @@ -119,6 +131,11 @@ bool knum_gtp(TValue n1, TValue n2) switch(max_ttype(n1, n2)) { case K_TFIXINT: return ivalue(n1) > ivalue(n2); + case K_TBIGINT: { + kensure_bigint(n1); + kensure_bigint(n2); + return kbigint_gtp(n1, n2); + } case K_TEINF: return !tv_equal(n1, n2) && (tv_equal(n1, KEPINF) || tv_equal(n2, KEMINF)); @@ -134,6 +151,11 @@ bool knum_gep(TValue n1, TValue n2) switch(max_ttype(n1, n2)) { case K_TFIXINT: return ivalue(n1) >= ivalue(n2); + case K_TBIGINT: { + kensure_bigint(n1); + kensure_bigint(n2); + return kbigint_ltp(n1, n2); + } case K_TEINF: return tv_equal(n1, n2) || tv_equal(n1, KEPINF) || tv_equal(n2, KEMINF); diff --git a/src/kinteger.c b/src/kinteger.c @@ -202,6 +202,74 @@ bool kbigint_eqp(TValue tv_bigint1, TValue tv_bigint2) return true; } +bool kbigint_ltp(TValue tv_bigint1, TValue tv_bigint2) +{ + Bigint *bigint1 = tv2bigint(tv_bigint1); + Bigint *bigint2 = tv2bigint(tv_bigint2); + + /* first take care of the easy sign cases */ + if (kbigint_negp(bigint1)) { + if (kbigint_posp(bigint2)) { + return true; + } else { + /* if both are negative reverse the order to compare + as positive */ + Bigint *temp = bigint1; + bigint1 = bigint2; + bigint2 = temp; + /* swap the tvalues just in case */ + TValue tv_temp = tv_bigint1; + tv_bigint1 = tv_bigint2; + tv_bigint2 = tv_temp; + } + } else if (kbigint_negp(bigint2)) { + return false; + } + + /* the the easy size cases */ + int32_t size1 = kbigint_size(bigint1); + int32_t size2 = kbigint_size(bigint2); + + if (size1 < size2) + return true; + else if (size1 > size2) + return false; + + /* size and sign equal, iterate in big endian mode */ + bind_iter(iter1, bigint1, true); + bind_iter(iter2, bigint2, true); + + while(iter_has_next(iter1) && iter_has_next(iter2)) { + uint32_t digit1 = iter_next(iter1); + uint32_t digit2 = iter_next(iter2); + if (digit1 < digit2) + return true; + else if (digit1 > digit2) + return false; + /* if equal we keep comparing */ + } + + return false; +} + +bool kbigint_lep(TValue tv_bigint1, TValue tv_bigint2) +{ + /* a <= b == !(a > b) == !(b < a) */ + return !kbigint_ltp(tv_bigint2, tv_bigint1); +} + +bool kbigint_gtp(TValue tv_bigint1, TValue tv_bigint2) +{ + /* a > b == (b < a) */ + return kbigint_ltp(tv_bigint2, tv_bigint1); +} + +bool kbigint_gep(TValue tv_bigint1, TValue tv_bigint2) +{ + /* a >= b == !(a < b) */ + return !kbigint_ltp(tv_bigint1, tv_bigint2); +} + bool kbigint_negativep(TValue tv_bigint) { return kbigint_negp(tv2bigint(tv_bigint)); @@ -209,6 +277,7 @@ bool kbigint_negativep(TValue tv_bigint) /* unlike the positive? applicative this would return true on zero, but zero is never represented as a bigint so there is no problem */ +/* XXX: but bigints constructed from fixints could be, clean this up */ bool kbigint_positivep(TValue tv_bigint) { return kbigint_posp(tv2bigint(tv_bigint)); diff --git a/src/kinteger.h b/src/kinteger.h @@ -25,17 +25,29 @@ TValue kbigint_copy(klisp_State *K, TValue src); useful for mixed operations, relatively light weight compared to creating it in the heap and burdening the gc */ #define kbind_bigint(name, fixint) \ - int32_t (KUNIQUE_NAME(i)) = fixint; \ - BigintNode KUNIQUE_NAME(node); \ - node.val = { int64_t temp = (KUNIQUE_NAME(i)); \ - (uint32_t) (temp < 0)? -temp : temp; }; \ - node.next_xor_prev = (uintptr_t) 0; /* NULL ^ NULL: 0 */ \ + int32_t (KUNIQUE_NAME(i)) = ivalue(fixint); \ + Bigint_Node KUNIQUE_NAME(node); \ + (KUNIQUE_NAME(node)).digit = ({ \ + int64_t temp = (KUNIQUE_NAME(i)); \ + (uint32_t) ((temp < 0)? -temp : temp); \ + }); \ + /* NULL ^ NULL: 0 */ \ + (KUNIQUE_NAME(node)).next_xor_prev = (uintptr_t) 0; \ Bigint KUNIQUE_NAME(bigint); \ (KUNIQUE_NAME(bigint)).first = &(KUNIQUE_NAME(node)); \ (KUNIQUE_NAME(bigint)).last = &(KUNIQUE_NAME(node)); \ (KUNIQUE_NAME(bigint)).sign_size = (KUNIQUE_NAME(i)) < 0? -1 : 1; \ Bigint *name = &(KUNIQUE_NAME(bigint)); +/* This can be used prior to calling a bigint functions + to automatically convert fixints to bigints. + NOTE: calls to this macro should go in different lines! */ +#define kensure_bigint(n) \ + if (ttisfixint(n)) { \ + kbind_bigint(KUNIQUE_NAME(bint), n); \ + n = gc2bigint(KUNIQUE_NAME(bint)); \ + } + /* This is used by the reader to destructively add digits to a number tv_bigint must be positive */ void kbigint_add_digit(klisp_State *K, TValue tv_bigint, int32_t base, @@ -50,6 +62,11 @@ bool kbigint_has_digits(klisp_State *K, TValue tv_bigint); bool kbigint_eqp(TValue bigint1, TValue bigint2); +bool kbigint_ltp(TValue bigint1, TValue bigint2); +bool kbigint_lep(TValue bigint1, TValue bigint2); +bool kbigint_gtp(TValue bigint1, TValue bigint2); +bool kbigint_gep(TValue bigint1, TValue bigint2); + bool kbigint_negativep(TValue tv_bigint); bool kbigint_positivep(TValue tv_bigint);