| 1 | ;; Mathematical functions |
|---|
| 2 | ;; Liam Healy, Wed Mar 8 2006 - 22:09 |
|---|
| 3 | ;; Time-stamp: <2008-02-17 09:13:19EST mathematical.lisp> |
|---|
| 4 | ;; $Id$ |
|---|
| 5 | |
|---|
| 6 | (in-package :gsl) |
|---|
| 7 | |
|---|
| 8 | ;;; Disable floating point traps for each CL implementation. |
|---|
| 9 | |
|---|
| 10 | ;;; Not ported because they are all C macros or inline functions: |
|---|
| 11 | ;;; Mathematical Constants |
|---|
| 12 | ;;; Testing the Sign of Numbers |
|---|
| 13 | ;;; Testing for Odd and Even Numbers |
|---|
| 14 | ;;; Maximum and Minimum functions |
|---|
| 15 | ;;; Does CL need the small integer powers? |
|---|
| 16 | |
|---|
| 17 | ;;;;**************************************************************************** |
|---|
| 18 | ;;; Infinities and Not-a-number |
|---|
| 19 | ;;;;**************************************************************************** |
|---|
| 20 | |
|---|
| 21 | (defmacro pmnil (x) |
|---|
| 22 | "+1, -1, or nil" |
|---|
| 23 | `(let ((v ,x)) |
|---|
| 24 | (when (or (= 1 v) (= -1 v)) |
|---|
| 25 | v))) |
|---|
| 26 | |
|---|
| 27 | #+sbcl |
|---|
| 28 | (eval-when (:compile-toplevel :load-toplevel :execute) |
|---|
| 29 | (sb-int:set-floating-point-modes :traps nil) |
|---|
| 30 | (import |
|---|
| 31 | '(sb-ext:double-float-negative-infinity |
|---|
| 32 | sb-ext:double-float-positive-infinity))) |
|---|
| 33 | |
|---|
| 34 | (export '(+nan+ +positive-infinity+ +negative-infinity+)) |
|---|
| 35 | |
|---|
| 36 | (defconstant +nan+ |
|---|
| 37 | (ignore-errors |
|---|
| 38 | (cffi:foreign-funcall "gsl_nan" :double))) |
|---|
| 39 | |
|---|
| 40 | (defconstant +positive-infinity+ |
|---|
| 41 | (ignore-errors |
|---|
| 42 | (cffi:foreign-funcall "gsl_posinf" :double))) |
|---|
| 43 | |
|---|
| 44 | (defconstant +negative-infinity+ |
|---|
| 45 | (ignore-errors |
|---|
| 46 | (cffi:foreign-funcall "gsl_neginf" :double))) |
|---|
| 47 | |
|---|
| 48 | (defmfun nanp (x) |
|---|
| 49 | "gsl_isnan" ((x :double)) |
|---|
| 50 | :c-return (cr :int) |
|---|
| 51 | :return ((= 1 cr)) |
|---|
| 52 | :documentation ; FDL |
|---|
| 53 | "Return T if x is a double-float NaN.") |
|---|
| 54 | |
|---|
| 55 | (defmfun infinityp (x) |
|---|
| 56 | "gsl_isinf" ((x :double)) |
|---|
| 57 | :c-return (cr :int) |
|---|
| 58 | :return ((pmnil cr)) |
|---|
| 59 | :documentation ; FDL |
|---|
| 60 | "Return +1 if x is positive infinity, -1 if negative infinity |
|---|
| 61 | nil if finite.") |
|---|
| 62 | |
|---|
| 63 | (defmfun finitep (x) |
|---|
| 64 | "gsl_finite" ((x :double)) |
|---|
| 65 | :c-return (cr :int) |
|---|
| 66 | :return ((= 1 cr)) |
|---|
| 67 | :documentation ; FDL |
|---|
| 68 | "Return T if x is finite.") |
|---|
| 69 | |
|---|
| 70 | ;;;;**************************************************************************** |
|---|
| 71 | ;;; Elementary functions |
|---|
| 72 | ;;;;**************************************************************************** |
|---|
| 73 | |
|---|
| 74 | (defmfun log+1 (x) |
|---|
| 75 | "gsl_log1p" ((x :double)) |
|---|
| 76 | :c-return :double |
|---|
| 77 | :documentation ; FDL |
|---|
| 78 | "log(1+x), computed in a way that is accurate for small x.") |
|---|
| 79 | |
|---|
| 80 | (defmfun exp-1 (x) |
|---|
| 81 | "gsl_expm1" ((x :double)) |
|---|
| 82 | :c-return :double |
|---|
| 83 | :documentation ; FDL |
|---|
| 84 | "exp(x)-1, computed in a way that is accurate for small x.") |
|---|
| 85 | |
|---|
| 86 | (defmfun hypotenuse* (x y) |
|---|
| 87 | ;; This is redundant; there is "gsl_sf_hypot_e" defined as |
|---|
| 88 | ;; #'hyptoenuse. |
|---|
| 89 | "gsl_hypot" ((x :double) (y :double)) |
|---|
| 90 | :c-return :double |
|---|
| 91 | :documentation ;FDL |
|---|
| 92 | "The hypotenuse sqrt{x^2 + y^2} computed in a way that avoids overflow.") |
|---|
| 93 | |
|---|
| 94 | ;; Not clear why this function exists |
|---|
| 95 | (defmfun gsl-asinh (x) |
|---|
| 96 | "gsl_asinh" ((x :double)) |
|---|
| 97 | :c-return :double |
|---|
| 98 | :documentation ; FDL |
|---|
| 99 | "Arc hyperbolic sine.") |
|---|
| 100 | |
|---|
| 101 | ;; Not clear why this function exists |
|---|
| 102 | (defmfun gsl-atanh (x) |
|---|
| 103 | "gsl_atanh" ((x :double)) |
|---|
| 104 | :c-return :double |
|---|
| 105 | :documentation ; FDL |
|---|
| 106 | "Arc hyperbolic tangent.") |
|---|
| 107 | |
|---|
| 108 | ;;; gsl_ldexp |
|---|
| 109 | ;;; gsl_frexp |
|---|
| 110 | ;;; not mapped because CL has equivalents. |
|---|
| 111 | |
|---|
| 112 | ;;;;**************************************************************************** |
|---|
| 113 | ;;; Small integer powers |
|---|
| 114 | ;;;;**************************************************************************** |
|---|
| 115 | |
|---|
| 116 | ;;; Does CL need these? |
|---|
| 117 | |
|---|
| 118 | #| |
|---|
| 119 | ;; FDL |
|---|
| 120 | A common complaint about the standard C library is its lack of a |
|---|
| 121 | function for calculating (small) integer powers. GSL provides a |
|---|
| 122 | simple functions to fill this gap. For reasons of efficiency, |
|---|
| 123 | these functions do not check for overflow or underflow |
|---|
| 124 | conditions. |
|---|
| 125 | |
|---|
| 126 | Function: double gsl_pow_int (double x, int n) |
|---|
| 127 | This routine computes the power x^n for integer n. The power is computed efficiently--for example, x^8 is computed as ((x^2)^2)^2, requiring only 3 multiplications. A version of this function which also computes the numerical error in the result is available as gsl_sf_pow_int_e. |
|---|
| 128 | |
|---|
| 129 | Function: double gsl_pow_2 (const double x) |
|---|
| 130 | Function: double gsl_pow_3 (const double x) |
|---|
| 131 | Function: double gsl_pow_4 (const double x) |
|---|
| 132 | Function: double gsl_pow_5 (const double x) |
|---|
| 133 | Function: double gsl_pow_6 (const double x) |
|---|
| 134 | Function: double gsl_pow_7 (const double x) |
|---|
| 135 | Function: double gsl_pow_8 (const double x) |
|---|
| 136 | Function: double gsl_pow_9 (const double x) |
|---|
| 137 | These functions can be used to compute small integer powers x^2, x^3, etc. efficiently. The functions will be inlined when possible so that use of these functions should be as efficient as explicitly writing the corresponding product expression. |
|---|
| 138 | |
|---|
| 139 | |# |
|---|
| 140 | |
|---|
| 141 | ;;;; Testing the Sign of Numbers |
|---|
| 142 | ;;; is all macros |
|---|
| 143 | |
|---|
| 144 | ;;;; Testing for Odd and Even Numbers |
|---|
| 145 | ;;; is all macros |
|---|
| 146 | |
|---|
| 147 | ;;;; Maximum and Minimum functions |
|---|
| 148 | ;;; is all macros and inline functions that have CL equivalents |
|---|
| 149 | |
|---|
| 150 | ;;;;**************************************************************************** |
|---|
| 151 | ;;; Approximate Comparison of Floating Point Numbers |
|---|
| 152 | ;;;;**************************************************************************** |
|---|
| 153 | |
|---|
| 154 | ;;; FDL |
|---|
| 155 | ;;; It is sometimes useful to be able to compare two floating point |
|---|
| 156 | ;;; numbers approximately, to allow for rounding and truncation |
|---|
| 157 | ;;; errors. This function implements the approximate |
|---|
| 158 | ;;; floating-point comparison algorithm proposed by D.E. Knuth in |
|---|
| 159 | ;;; Section 4.2.2 of Seminumerical Algorithms (3rd edition). |
|---|
| 160 | |
|---|
| 161 | (defmfun double-float-unequal (x y epsilon) |
|---|
| 162 | "gsl_fcmp" ((x :double) (y :double) (epsilon :double)) |
|---|
| 163 | :c-return (cr :int) |
|---|
| 164 | :documentation ; FDL |
|---|
| 165 | "This function determines whether x and y are approximately equal |
|---|
| 166 | to a relative accuracy epsilon. |
|---|
| 167 | |
|---|
| 168 | The relative accuracy is measured using an interval of size 2 |
|---|
| 169 | delta, where delta = 2^k \epsilon and k is the maximum |
|---|
| 170 | base-2 exponent of x and y as computed by the function |
|---|
| 171 | frexp(). |
|---|
| 172 | |
|---|
| 173 | If x and y lie within this interval, they are considered |
|---|
| 174 | approximately equal and the function returns nil. Otherwise if |
|---|
| 175 | x < y, the function returns -1, or if x > y, the function |
|---|
| 176 | returns +1." |
|---|
| 177 | :return ((pmnil cr))) |
|---|
| 178 | |
|---|
| 179 | ;;;;**************************************************************************** |
|---|
| 180 | ;;;; Examples and unit test |
|---|
| 181 | ;;;;**************************************************************************** |
|---|
| 182 | |
|---|
| 183 | #| |
|---|
| 184 | (make-tests mathematical |
|---|
| 185 | (log+1 0.001d0) |
|---|
| 186 | (exp-1 0.001d0) |
|---|
| 187 | (hypotenuse 3.0d0 4.0d0)) |
|---|
| 188 | |# |
|---|
| 189 | |
|---|
| 190 | (lisp-unit:define-test mathematical |
|---|
| 191 | (lisp-unit:assert-true (nanp +nan+)) |
|---|
| 192 | (lisp-unit:assert-false (nanp 1.0d0)) |
|---|
| 193 | (lisp-unit:assert-true (finitep 1.0d0)) |
|---|
| 194 | (lisp-unit:assert-false (infinityp 1.0d0)) |
|---|
| 195 | (lisp-unit:assert-eq 1 (infinityp +positive-infinity+)) |
|---|
| 196 | (lisp-unit:assert-false (finitep +positive-infinity+)) |
|---|
| 197 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 198 | (LIST 9.995003330835331d-4) |
|---|
| 199 | (MULTIPLE-VALUE-LIST (LOG+1 0.001d0))) |
|---|
| 200 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 201 | (LIST 0.0010005001667083417d0) |
|---|
| 202 | (MULTIPLE-VALUE-LIST (EXP-1 0.001d0))) |
|---|
| 203 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 204 | (LIST 5.0d0 2.220446049250313d-15) |
|---|
| 205 | (MULTIPLE-VALUE-LIST (HYPOTENUSE 3.0d0 4.0d0))) |
|---|
| 206 | (lisp-unit:assert-false (double-float-unequal 1.0d0 1.0d0 0.001d0))) |
|---|