diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-03-09 11:42:11 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-03-09 11:42:11 -0800 |
commit | 285e3a5c375774135c29c6b7ff3b4b811b6cacd1 (patch) | |
tree | c032fa7aae6fcc31aef3d62d9a452d6f6d9822fc | |
parent | e844d3a602af4380c196d896b803b67d58ecbcea (diff) | |
download | txr-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.
-rw-r--r-- | arith.c | 70 | ||||
-rw-r--r-- | txr.1 | 15 |
2 files changed, 66 insertions, 19 deletions
@@ -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) @@ -35531,6 +35531,9 @@ follows, then that value is divided by that subsequent divisor. This process repeats until all divisors are exhausted, and the value of the last division is returned. +A division by zero throws an exception of type +.codn numeric-error . + .coNP Functions @ sum and @ prod .synb .mets (sum < sequence <> [ keyfun ]) @@ -36037,8 +36040,16 @@ similarly to the way nested exponents work in standard algebraic notation. Exponentiation is done pairwise using a binary operation. -If both operands to this binary operation are integers, then the -result is an integer. If either operand is a float, then the other +If both operands to this binary operation are non-negative integers, then the +result is an integer. + +If the exponent is negative, and the base is zero, the situation is +treated as a division by zero: an exception of type +.code numeric-error +is thrown. Otherwise, a negative exponent is converted to floating-point, +if it already isn't, and a floating-point exponentiation is performed. + +If either operand is a float, then the other operand is converted to a float, and a floating point exponentiation is performed. Exponentiation that would produce a complex number is not supported. |