diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | arith.c | 65 | ||||
-rw-r--r-- | lib.c | 13 |
3 files changed, 68 insertions, 17 deletions
@@ -1,5 +1,12 @@ 2011-12-11 Kaz Kylheku <kaz@kylheku.com> + * arith.c (trunc): Error messages prefixed with trunc:. + (mod): New function, reimplementation of removed mod from lib.c. + + * lib.c (mod): Function removed. + +2011-12-11 Kaz Kylheku <kaz@kylheku.com> + Bignum division implemented. More portability bugs found in MPI: code like 1 << n, where n exceeds the width of the type int. @@ -512,7 +512,7 @@ val trunc(val anum, val bnum) int neg = ((a < 0 && b > 0) || (a > 0 && b < 0)); if (b == 0) - uw_throw(numeric_error_s, lit("division by zero")); + uw_throw(numeric_error_s, lit("trunc: division by zero")); { cnum quot = ap / bp; @@ -531,7 +531,7 @@ val trunc(val anum, val bnum) cnum b = c_num(bnum); cnum bp = ABS(b); if (mp_div_d(mp(anum), bp, mp(n), 0) != MP_OKAY) - uw_throw(numeric_error_s, lit("division by zero")); + uw_throw(numeric_error_s, lit("trunc: division by zero")); if (b < 0) mp_neg(mp(n), mp(n)); } else { @@ -539,7 +539,7 @@ val trunc(val anum, val bnum) mp_init(&tmp); mp_set_intptr(&tmp, c_num(bnum)); if (mp_div(mp(anum), &tmp, mp(n), 0) != MP_OKAY) - uw_throw(numeric_error_s, lit("division by zero")); + uw_throw(numeric_error_s, lit("trunc: division by zero")); } return normalize(n); } @@ -550,7 +550,7 @@ val trunc(val anum, val bnum) type_check(bnum, BGNUM); n = make_bignum(); if (mp_div(mp(anum), mp(bnum), mp(n), 0) != MP_OKAY) - uw_throw(numeric_error_s, lit("division by zero")); + uw_throw(numeric_error_s, lit("trunc: division by zero")); return normalize(n); } } @@ -558,6 +558,63 @@ val trunc(val anum, val bnum) abort(); } +val mod(val anum, val bnum) +{ + int tag_a = tag(anum); + int tag_b = tag(bnum); + + switch (TAG_PAIR(tag_a, tag_b)) { + case TAG_PAIR(TAG_NUM, TAG_NUM): + { + cnum a = c_num(anum); + cnum b = c_num(bnum); + + if (b == 0) + uw_throw(numeric_error_s, lit("mod: division by zero")); + + { + cnum m = a % b; + return num(m < 0 ? m + ABS(b) : m); + } + } + case TAG_PAIR(TAG_NUM, TAG_PTR): + type_check(bnum, BGNUM); + return zero; + case TAG_PAIR(TAG_PTR, TAG_NUM): + { + type_check(anum, BGNUM); + if (sizeof (int_ptr_t) <= sizeof (mp_digit)) { + cnum b = c_num(bnum); + cnum bp = ABS(b); + mp_digit n; + if (mp_mod_d(mp(anum), bp, &n) != MP_OKAY) + uw_throw(numeric_error_s, lit("mod: division by zero")); + return num(n); + } else { + val n = make_bignum(); + mp_int tmp; + mp_init(&tmp); + mp_set_intptr(&tmp, c_num(bnum)); + if (mp_mod(mp(anum), &tmp, mp(n)) != MP_OKAY) + uw_throw(numeric_error_s, lit("mod: division by zero")); + return normalize(n); + } + } + case TAG_PAIR(TAG_PTR, TAG_PTR): + { + val n; + type_check(anum, BGNUM); + type_check(bnum, BGNUM); + n = make_bignum(); + if (mp_mod(mp(anum), mp(bnum), mp(n)) != MP_OKAY) + uw_throw(numeric_error_s, lit("mod: division by zero")); + return normalize(n); + } + } + uw_throwf(error_s, lit("mod: invalid operands ~s ~s"), anum, bnum, nao); + abort(); +} + void arith_init(void) { mp_init(&NUM_MAX_MP); @@ -857,19 +857,6 @@ val mulv(val nlist) return reduce_left(func_n2(mul), cdr(nlist), car(nlist), nil); } -val mod(val anum, val bnum) -{ - cnum a = c_num(anum); - cnum b = c_num(bnum); - - numeric_assert (b != 0); - - { - cnum result = a % b; - return num(result); - } -} - val zerop(val num) { return c_num(num) == 0 ? t : nil; |