commit 999e1c70846070ad2bd95bb7587ac5141a42e9c9
parent df628c2d7effbec7fd278417a9af73b487cd9691
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Wed, 27 Apr 2011 17:49:13 -0300
Added rational support to div-and-mod.
Diffstat:
3 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/src/kgnumbers.c b/src/kgnumbers.c
@@ -804,7 +804,7 @@ void kdiv_mod(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
     UNUSED(denv);
 
     bind_2tp(K, name, ptree, "real", krealp, tv_n,
-	     "number", krealp, tv_d);
+	     "real", krealp, tv_d);
 
     TValue tv_div, tv_mod;
 
@@ -842,6 +842,14 @@ void kdiv_mod(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
 	else
 	    tv_div = kbigint_div0_mod0(K, tv_n, tv_d, &tv_mod);
 	break;
+    case K_TBIGRAT:
+	kensure_bigrat(tv_n);
+	kensure_bigrat(tv_d);
+	if ((flags & FDIV_ZERO) == 0)
+	    tv_div = kbigrat_div_mod(K, tv_n, tv_d, &tv_mod);
+	else /* TODO */
+	    tv_div = kbigrat_div0_mod0(K, tv_n, tv_d, &tv_mod);
+	break;
     case K_TEINF:
 	if (ttiseinf(tv_n)) {
 	    klispE_throw_extra(K, name, ": non finite dividend");
@@ -1054,7 +1062,6 @@ void klcm(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
     UNUSED(xparams);
     UNUSED(denv);
     /* cycles are allowed, loop counting pairs */
-    int32_t dummy; /* don't care about count of cycle pairs */
     int32_t pairs = check_typed_list(K, "lcm", "improper integer", kimp_intp, 
 				     true, ptree, NULL);
 
diff --git a/src/krational.c b/src/krational.c
@@ -189,6 +189,64 @@ TValue kbigrat_minus(klisp_State *K, TValue n1, TValue n2)
     return kbigrat_try_integer(K, res);
 }
 
+/* NOTE: n2 can't be zero, that case should be checked before calling this */
+TValue kbigrat_div_mod(klisp_State *K, TValue n1, TValue n2, TValue *res_r)
+{
+    /* NOTE: quotient is always an integer, remainder may be any rational */
+    /* the remainder is calculated as tv_r * n2 */
+    TValue tv_q = kbigint_make_simple(K);
+    krooted_tvs_push(K, tv_q);
+    TValue tv_r = kbigint_make_simple(K);
+    krooted_tvs_push(K, tv_r);
+    /* for temp values */
+    TValue tv_true_rem = kbigrat_make_simple(K);
+    krooted_tvs_push(K, tv_true_rem);
+    TValue tv_div = kbigrat_make_simple(K);
+    krooted_tvs_push(K, tv_div);
+
+    Bigrat *n = tv2bigrat(n1);
+    Bigrat *d = tv2bigrat(n2);
+
+    Bigint *q = tv2bigint(tv_q);
+    Bigint *r = tv2bigint(tv_r);
+
+    Bigrat *div = tv2bigrat(tv_div);
+    Bigrat *trem = tv2bigrat(tv_true_rem);
+
+    UNUSED(mp_rat_div(K, n, d, div));
+
+    /* Now use the integral part as the quotient and the fractional part times
+       the divisor as the remainder, but then correct the remainder so that it's
+       always positive like in kbigint_div_and_mod */
+       
+    UNUSED(mp_int_div(K, MP_NUMER_P(div), MP_DENOM_P(div), q, r));
+
+    /* NOTE: denom is positive, so div & q & r have the same sign */
+
+    /* first adjust the quotient if necessary,
+       the remainder will just fall into place after this */
+    if (mp_rat_compare_zero(n) < 0)
+	UNUSED(mp_int_add_value(K, q, mp_rat_compare_zero(d) < 0? 1 : -1, q));
+
+    UNUSED(mp_rat_sub_int(K, div, q, trem));
+    UNUSED(mp_rat_mul(K, trem, d, trem));
+
+    krooted_tvs_pop(K);
+    krooted_tvs_pop(K);
+    krooted_tvs_pop(K);
+    krooted_tvs_pop(K);
+
+    *res_r = kbigrat_try_integer(K, tv_true_rem);
+    return kbigrat_try_integer(K, tv_q);
+}
+
+TValue kbigrat_div0_mod0(klisp_State *K, TValue n1, TValue n2, TValue *res_r)
+{
+    /* TODO */
+    return KINERT;
+}
+
+
 TValue kbigrat_divided(klisp_State *K, TValue n1, TValue n2)
 {
     TValue res = kbigrat_make_simple(K);
diff --git a/src/krational.h b/src/krational.h
@@ -151,11 +151,8 @@ TValue kbigrat_times(klisp_State *K, TValue n1, TValue n2);
 TValue kbigrat_minus(klisp_State *K, TValue n1, TValue n2);
 TValue kbigrat_divided(klisp_State *K, TValue n1, TValue n2);
 
-/* TODO: Kernel allows arbitrary reals for these... will have to define */
-#if 0
 TValue kbigrat_div_mod(klisp_State *K, TValue n1, TValue n2, TValue *res_r);
 TValue kbigrat_div0_mod0(klisp_State *K, TValue n1, TValue n2, TValue *res_r);
-#endif
 
 bool kbigrat_negativep(TValue tv_bigrat);
 bool kbigrat_positivep(TValue tv_bigrat);