diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index c2e0317a..12bfbb97 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -179,6 +179,7 @@ object Cyc_num_cmp_va_list(void *data, int argc, int (fn_op(void *, object, object)), object n, va_list ns); void Cyc_expt(void *data, object cont, object x, object y); +void Cyc_remainder(void *data, object cont, object num1, object num2); object Cyc_eq(object x, object y); object Cyc_set_cell(void *, object l, object val); object Cyc_set_car(void *, object l, object val); diff --git a/runtime.c b/runtime.c index 13c7a8d3..8c0921b3 100644 --- a/runtime.c +++ b/runtime.c @@ -3196,6 +3196,68 @@ void Cyc_expt(void *data, object cont, object x, object y) Cyc_rt_raise(data, &c0); } +void Cyc_bignum_remainder(void *data, object cont, object num1, object num2, object rem) +{ + mp_div(&bignum_value(num1), &bignum_value(num2), NULL, &bignum_value(rem)); + return_closcall1(data, cont, Cyc_bignum_normalize(data, rem)); +} + +void Cyc_remainder(void *data, object cont, object num1, object num2) +{ + int i = 0, j = 0; + object result; + Cyc_check_num(data, num1); + Cyc_check_num(data, num2); + if (obj_is_int(num1)) { + if (obj_is_int(num2)){ + i = obj_obj2int(num1); + j = obj_obj2int(num2); + } + else if (is_object_type(num2) && type_of(num2) == bignum_tag){ + alloc_bignum(data, bn); + Cyc_int2bignum(obj_obj2int(num1), &(bn->bn)); + Cyc_bignum_remainder(data, cont, bn, num2, bn); + } + else { + i = obj_obj2int(num1); + j = ((double_type *)num2)->value; + } + } else if (is_object_type(num1) && type_of(num1) == bignum_tag) { + if (obj_is_int(num2)){ + alloc_bignum(data, bn); + Cyc_int2bignum(obj_obj2int(num2), &(bn->bn)); + Cyc_bignum_remainder(data, cont, num1, bn, bn); + } + else if (is_object_type(num2) && type_of(num2) == bignum_tag){ + alloc_bignum(data, rem); + Cyc_bignum_remainder(data, cont, num1, num2, rem); + } + else { + j = ((double_type *)num2)->value; + alloc_bignum(data, bn); + Cyc_int2bignum(obj_obj2int(j), &(bn->bn)); + Cyc_bignum_remainder(data, cont, num1, bn, bn); + } + } else { // num1 is double... + if (obj_is_int(num2)){ + i = ((double_type *)num1)->value; + j = obj_obj2int(num2); + } + else if (is_object_type(num2) && type_of(num2) == bignum_tag){ + i = ((double_type *)num1)->value; + alloc_bignum(data, bn); + Cyc_int2bignum(obj_obj2int(i), &(bn->bn)); + Cyc_bignum_remainder(data, cont, bn, num2, bn); + } + else { + i = ((double_type *)num1)->value; + j = ((double_type *)num2)->value; + } + } + result = obj_int2obj(i % j); + return_closcall1(data, cont, result); +} + /* I/O functions */ port_type Cyc_stdout()