summaryrefslogtreecommitdiffstats
path: root/arith.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-12-10 20:41:06 -0800
committerKaz Kylheku <kaz@kylheku.com>2011-12-10 20:41:06 -0800
commit858859cf6fd6becef038cf4d9c1e650c3f2a9cc6 (patch)
tree081517aa9628b45d86e7fb1e139e3da996bdc89b /arith.c
parentc940739b8f863f3331f00b36c23ad1526ab1147e (diff)
downloadtxr-858859cf6fd6becef038cf4d9c1e650c3f2a9cc6.tar.gz
txr-858859cf6fd6becef038cf4d9c1e650c3f2a9cc6.tar.bz2
txr-858859cf6fd6becef038cf4d9c1e650c3f2a9cc6.zip
Bignum support in mult function.
* arith.c: Regenerated. * arith.txr (CNUM_BIT): New constant. (bignum, bignum_dbl_ipt): New static functions. (@{add-fname}): Use bignum function. (mul): New functions, rewrite of mul from lib.c. * lib.c (mul): Function removed. * mpi-patches/add-mp-set-intptr (mp_set_intptr): Revised patch. Local variable v should be int_ptr_t not unsigned long. Also, the mp_set interface doesn't set the sign; it's an unsigned interface. We must do that ourselves. * mpi-patches/fix-mult-bug: The main multiplication function is also broken in the same way, requiring the cast. * mpi-patches/mpi-set-double-intptr: Fixed use of wrong type for local variable v.
Diffstat (limited to 'arith.c')
-rw-r--r--arith.c123
1 files changed, 111 insertions, 12 deletions
diff --git a/arith.c b/arith.c
index f13d067e..bf7f867f 100644
--- a/arith.c
+++ b/arith.c
@@ -37,6 +37,7 @@
#include <dirent.h>
#include <setjmp.h>
#include <wchar.h>
+#include <limits.h>
#include "config.h"
#include "lib.h"
#include "unwind.h"
@@ -45,6 +46,7 @@
#define TAG_PAIR(A, B) ((A) << TAG_SHIFT | (B))
#define NOOP(A, B)
+#define CNUM_BIT ((int) sizeof (cnum) * CHAR_BIT)
static mp_int NUM_MAX_MP;
@@ -56,6 +58,20 @@ val make_bignum(void)
return n;
}
+static val bignum(cnum cn)
+{
+ val n = make_bignum();
+ mp_set_intptr(mp(n), cn);
+ return n;
+}
+
+static val bignum_dbl_ipt(double_intptr_t di)
+{
+ val n = make_bignum();
+ mp_set_double_intptr(mp(n), di);
+ return n;
+}
+
static val normalize(val bignum)
{
switch (mp_cmp_mag(mp(bignum), &NUM_MAX_MP)) {
@@ -83,12 +99,8 @@ val plus(val anum, val bnum)
cnum b = c_num(bnum);
cnum sum = a + b;
- if (sum < NUM_MIN || sum > NUM_MAX) {
- val n = make_bignum();
- mp_set_intptr(mp(n), sum);
- return n;
- }
-
+ if (sum < NUM_MIN || sum > NUM_MAX)
+ return bignum(sum);
return num(sum);
}
case TAG_PAIR(TAG_NUM, TAG_PTR):
@@ -148,12 +160,8 @@ val minus(val anum, val bnum)
cnum b = c_num(bnum);
cnum sum = a - b;
- if (sum < NUM_MIN || sum > NUM_MAX) {
- val n = make_bignum();
- mp_set_intptr(mp(n), sum);
- return n;
- }
-
+ if (sum < NUM_MIN || sum > NUM_MAX)
+ return bignum(sum);
return num(sum);
}
case TAG_PAIR(TAG_NUM, TAG_PTR):
@@ -213,6 +221,97 @@ val neg(val anum)
}
}
+val mul(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 HAVE_DOUBLE_INTPTR_T
+ double_intptr_t product = a * (double_intptr_t) b;
+ if (product < NUM_MIN || product > NUM_MAX)
+ return bignum_dbl_ipt(product);
+ return num(product);
+#else
+ cnum ap = (a < 0) ? -a : a;
+ cnum bp = (b < 0) ? -b : b;
+ int bit = CNUM_BIT - 3, amaxbit = 0, bmaxbit = 0;
+ cnum mask = (cnum) 1 << (CNUM_BIT - 4);
+ for (; mask && (ap || bp); mask >>= 1, bit--) {
+ if ((ap & mask)) {
+ amaxbit = bit;
+ ap = 0;
+ }
+ if ((bp & mask)) {
+ bmaxbit = bit;
+ bp = 0;
+ }
+ }
+ if (amaxbit + bmaxbit < CNUM_BIT - 1) {
+ cnum product = a * b;
+ if (product >= NUM_MIN && product <= NUM_MAX)
+ return num(a * b);
+ return bignum(a * b);
+ } else {
+ val n = make_bignum();
+ mp_int tmpb;
+ mp_init(&tmpb);
+ mp_set_intptr(&tmpb, b);
+ mp_set_intptr(mp(n), a);
+ mp_mul(mp(n), &tmpb, mp(n));
+ mp_clear(&tmpb);
+ return n;
+ }
+#endif
+ }
+ case TAG_PAIR(TAG_NUM, TAG_PTR):
+ {
+ val n;
+ type_check(bnum, BGNUM);
+ n = make_bignum();
+ if (sizeof (int_ptr_t) <= sizeof (mp_digit)) {
+ mp_mul_d(mp(bnum), c_num(anum), mp(n));
+ } else {
+ mp_int tmp;
+ mp_init(&tmp);
+ mp_set_intptr(&tmp, c_num(anum));
+ mp_mul(mp(bnum), &tmp, mp(n));
+ }
+ return n;
+ }
+ case TAG_PAIR(TAG_PTR, TAG_NUM):
+ {
+ val n;
+ type_check(bnum, BGNUM);
+ n = make_bignum();
+ if (sizeof (int_ptr_t) <= sizeof (mp_digit)) {
+ mp_mul_d(mp(anum), c_num(bnum), mp(n));
+ } else {
+ mp_int tmp;
+ mp_init(&tmp);
+ mp_set_intptr(&tmp, c_num(bnum));
+ mp_mul(mp(anum), &tmp, mp(n));
+ }
+ return n;
+ }
+ case TAG_PAIR(TAG_PTR, TAG_PTR):
+ {
+ val n;
+ type_check(anum, BGNUM);
+ type_check(bnum, BGNUM);
+ n = make_bignum();
+ mp_mul(mp(anum), mp(bnum), mp(n));
+ return n;
+ }
+ }
+ uw_throwf(error_s, lit("mul: invalid operands ~s ~s"), anum, bnum, nao);
+ abort();
+}
+
void arith_init(void)
{
mp_init(&NUM_MAX_MP);