Raymond Toy pushed to branch master
at cmucl / cmucl
Commits:
-
f3b73541
by Raymond Toy
at 2016-01-01T09:30:18Z
Add special case for (expt 0 power)
We know the result of (expt 0 power) so return it immediately without
first checking if the power exceeds the limit.
Also took the opportunity to add a better message to the
intexp-limit-error condition to make it more explicit what is being
computed and why it's failing.
Tests added too.
2 changed files:
Changes:
src/code/irrat.lisp
--- a/src/code/irrat.lisp
+++ b/src/code/irrat.lisp
@@ -252,6 +252,13 @@
(return-from intexp base))
(when (eql base -1)
(return-from intexp (if (oddp power) -1 1)))
+
+ ;; Handle 0 raised to a power. Return 0 if the power is
+ ;; non-negative or signal a divide-by-zero if the power is negative.
+ (when (zerop base)
+ (if (minusp power)
+ (error 'division-by-zero)
+ (return-from intexp base)))
(when (> (abs power) *intexp-maximum-exponent*)
;; Allow user the option to continue with calculation, possibly
tests/irrat.lisp
--- a/tests/irrat.lisp
+++ b/tests/irrat.lisp
@@ -152,3 +152,23 @@
for logx = (kernel::dd-%log2 x)
for log1/x = (kernel::dd-%log2 (/ x))
do (assert-true (<= (abs (+ logx log1/x)) (* 1 double-float-epsilon)))))
+
+(define-test expt-integer
+ (let ((power (1+ kernel::*intexp-maximum-exponent*)))
+ ;; Make sure we error out in the usual case with the power too
+ ;; large.
+ (assert-error 'kernel::intexp-limit-error
+ (expt 2 power))
+ (assert-error 'kernel::intexp-limit-error
+ (expt 2 (- power)))
+ ;; But raising 0 or 1 to a power shouldn't signal anything, except
+ ;; the obvious division-by-zero.
+ (assert-eql 1 (expt 1 power))
+ (cond ((evenp power)
+ (assert-eql 1 (expt -1 power))
+ (assert-eql -1 (expt -1 (1+ power))))
+ (t
+ (assert-eql -1 (expt -1 power))
+ (assert-eql 1 (expt -1 (1+ power)))))
+ (assert-eql 0 (expt 0 power))
+ (assert-error 'division-by-zero (expt 0 (- power)))))