From 5f81e24180fa7721fcad38b9ae3419bd9f2a221d Mon Sep 17 00:00:00 2001 From: Raymond Toy <toy.raymond@gmail.com> Date: Sun, 30 Nov 2014 18:24:59 -0800 Subject: [PATCH] Fix to handle (log 3/2 2) and (log -3/2 2). Test added. * src/code/irrat.lisp: * Fix LOG2 to handle the case of negative rational numbers. * Fix LOG of rational to a rational base. We want to convert the log of the number to a single float because log2 isn't intended to handle single-float type. * tests/irrat.lisp: * Add test for log of rational to rational base. * Add some additional tests for dd-%log2. --- src/code/irrat.lisp | 11 +++++++---- tests/irrat.lisp | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/code/irrat.lisp b/src/code/irrat.lisp index 0804ef9ec..b21b92fbc 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 a6a405db8..14db13eeb 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))))) -- GitLab