diff --git a/src/code/irrat.lisp b/src/code/irrat.lisp index 0804ef9ec89a03164005a313173fccf6b6707e04..b21b92fbcebb0c2851722944e6c3b9e1d2d55a5c 100644 --- a/src/code/irrat.lisp +++ b/src/code/irrat.lisp @@ -632,8 +632,11 @@ ;; it, and converting it to double-float is accurate. (if (= (integer-length top) (integer-length bot)) - (/ (log1p (float (- x 1) float-type)) - (log-of-2 float-type)) + (let ((log-abs (/ (log1p (float (- (abs x) 1) float-type)) + (log-of-2 float-type)))) + (if (minusp x) + (complex log-abs (log-2-pi float-type)) + log-abs)) (multiple-value-bind (top-n top-frac) (log2-bignum top) (multiple-value-bind (bot-n bot-frac) @@ -687,10 +690,10 @@ (float (%log2 (float number 1d0)) 1f0)) (((foreach integer ratio) (foreach integer ratio single-float)) - (log2 number 1f0)) + (float (log2 number) 1f0)) (((foreach integer ratio) double-float) - (log2 number 1d0)) + (log2 number)) #+double-double (((foreach single-float double-float) double-double-float) diff --git a/tests/irrat.lisp b/tests/irrat.lisp index a6a405db8f6091cf275e3a2d6f4d234ab13be217..14db13eebbbb38da3701851f15b037ad08e5afe2 100644 --- a/tests/irrat.lisp +++ b/tests/irrat.lisp @@ -37,6 +37,22 @@ (assert-true (typep result true-type) result true-type))))) +(define-test log2.special-cases + (let* ((y (log 3/2 2)) + (e (relerr y 0.5849625007211562d0))) + (assert-true (<= e + 2.308d-8) + e y)) + (let* ((y (log -3/2 2)) + (ry (realpart y)) + (iy (imagpart y)) + (er (relerr ry 0.5849625007211562d0)) + (ei (relerr iy (/ pi (log 2d0))))) + (assert-true (<= er 2.308d-8) + er ry) + (assert-true (<= ei 1.433d-8) + ei iy))) + ;; This tests that log base 10 returns the correct value and the ;; correct type. (define-test log10.result-types @@ -129,3 +145,10 @@ do (assert-true (<= e threshold) k e x y)))) + +(define-test log2.relationships + (loop for k from 1 below 1000 + for x = (expt 1.1w0 k) + for logx = (kernel::dd-%log2 x) + for log1/x = (kernel::dd-%log2 (/ x)) + do (assert-true (<= (abs (+ logx log1/x)) (* 1 double-float-epsilon)))))