summaryrefslogtreecommitdiffstats
path: root/arith.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-03-09 11:42:11 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-03-09 11:42:11 -0800
commit285e3a5c375774135c29c6b7ff3b4b811b6cacd1 (patch)
treec032fa7aae6fcc31aef3d62d9a452d6f6d9822fc /arith.c
parente844d3a602af4380c196d896b803b67d58ecbcea (diff)
downloadtxr-285e3a5c375774135c29c6b7ff3b4b811b6cacd1.tar.gz
txr-285e3a5c375774135c29c6b7ff3b4b811b6cacd1.tar.bz2
txr-285e3a5c375774135c29c6b7ff3b4b811b6cacd1.zip
expt: handle negative integer exponents with integer bases.
* arith.c (expt): The function overhauled. Raising integers to negative integers now works. Raising zero to a negative is diagnosed as a division by zero for operands of all kinds. * txr.1: Documentation updated for expt, and also division by zero error is documented for the / function.
Diffstat (limited to 'arith.c')
-rw-r--r--arith.c70
1 files changed, 53 insertions, 17 deletions
diff --git a/arith.c b/arith.c
index 968d4a2c..d10878d5 100644
--- a/arith.c
+++ b/arith.c
@@ -1966,11 +1966,14 @@ tail:
mp_int tmpa;
val n;
mp_err mpe = MP_OKAY;
- if (b < 0)
- goto negexp;
- if (bnum == zero)
+ if (b < 0) {
+ if (anum == zero)
+ goto divzero;
+ return flo(pow(a, b));
+ }
+ if (b == 0)
return one;
- if (bnum == one)
+ if (b == 1)
return anum;
n = make_bignum();
mp_init(&tmpa);
@@ -1995,8 +1998,12 @@ tail:
mp_int tmpa;
val n;
mp_err mpe = MP_OKAY;
- if (mp_cmp_z(mp(bnum)) == MP_LT)
- goto negexp;
+ if (mp_cmp_z(mp(bnum)) == MP_LT) {
+ if (anum == zero)
+ goto divzero;
+ bnum = flo_int(bnum);
+ goto tail;
+ }
n = make_bignum();
mp_init(&tmpa);
mp_set_intptr(&tmpa, a);
@@ -2011,11 +2018,15 @@ tail:
cnum b = c_n(bnum);
val n;
mp_err mpe = MP_OKAY;
- if (b < 0)
- goto negexp;
- if (bnum == zero)
+ if (b < 0) {
+ if (mp_cmp_z(mp(anum)) == MP_LT)
+ goto divzero;
+ anum = flo_int(anum);
+ goto tail;
+ }
+ if (b == 0)
return one;
- if (bnum == one)
+ if (b == 1)
return anum;
n = make_bignum();
if (sizeof (int_ptr_t) <= sizeof (mp_digit)) {
@@ -2035,8 +2046,13 @@ tail:
{
val n;
mp_err mpe = MP_OKAY;
- if (mp_cmp_z(mp(bnum)) == MP_LT)
- goto negexp;
+ if (mp_cmp_z(mp(bnum)) == MP_LT) {
+ if (mp_cmp_z(mp(anum)) == MP_LT)
+ goto divzero;
+ anum = flo_int(anum);
+ bnum = flo_int(bnum);
+ goto tail;
+ }
n = make_bignum();
mpe = mp_expt(mp(anum), mp(bnum), mp(n));
if (mpe != MP_OKAY)
@@ -2045,12 +2061,32 @@ tail:
return n;
}
case TYPE_PAIR(NUM, FLNUM):
- /* TODO: error checking */
- return flo(pow(c_n(anum), c_flo(bnum, self)));
+ {
+ cnum a = c_n(anum);
+ double b = c_flo(bnum, self);
+
+ if (a == 0 && b < 0)
+ goto divzero;
+ return flo(pow(a, b));
+ }
case TYPE_PAIR(FLNUM, NUM):
+ {
+ double a = c_flo(anum, self);
+ cnum b = c_n(bnum);
+
+ if (a == 0 && b < 0)
+ goto divzero;
+ return flo(pow(a, b));
+ }
return flo(pow(c_flo(anum, self), c_n(bnum)));
case TYPE_PAIR(FLNUM, FLNUM):
- return flo(pow(c_flo(anum, self), c_flo(bnum, self)));
+ {
+ double a = c_flo(anum, self);
+ double b = c_flo(bnum, self);
+ if (a == 0 && b < 0)
+ goto divzero;
+ return flo(pow(a, b));
+ }
case TYPE_PAIR(BGNUM, FLNUM):
anum = flo_int(anum);
goto tail;
@@ -2060,8 +2096,8 @@ tail:
}
invalid_ops(self, anum, bnum);
-negexp:
- uw_throwf(type_error_s, lit("~a: negative exponent"), self, nao);
+divzero:
+ divzero(self);
}
val exptmod(val base, val exp, val mod)