;;; PLT Scheme Science Collection ;;; math.ss ;;; Copyright (c) 2004 M. Douglas Williams ;;; ;;; This library is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU Lesser General Public ;;; License as published by the Free Software Foundation; either ;;; version 2.1 of the License, or (at your option) any later version. ;;; ;;; This library is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; Lesser General Public License for more details. ;;; ;;; You should have received a copy of the GNU Lesser General Public ;;; License along with this library; if not, write to the Free ;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ;;; 02111-1307 USA. ;;; ;;; ------------------------------------------------------------------- ;;; ;;; This code is based on the Mathematical Functions in the GNU ;;; Scientific Library (GSL). ;;; ;;; Version Date Description ;;; 0.1.0 08/13/04 This is the initial realease of the ;;; mathematical function routines ported from GSL. ;;; (Doug Williams) ;;; 1.0.0 09/28/04 Removed the code for small integer powers. ;;; Marked as ready for Release 1.0. Added ;;; contracts for functions (Doug Williams) (module math mzscheme (require (lib "contract.ss")) (provide e log2e log10e sqrt2 sqrt1/2 sqrt3 pi pi/2 pi/4 sqrtpi 2/sqrtpi 1/pi 2/pi ln10 ln2 lnpi euler) (provide/contract (nan? (-> any/c boolean?)) (infinite? (-> any/c (union (integer-in -1 1) boolean?))) (finite? (-> any/c boolean?)) (log1p (-> real? number?)) (expm1 (-> real? real?)) (hypot (-> real? real? real?)) (acosh (-> real? real?)) (asinh (-> real? real?)) (atanh (-> real? real?)) (ldexp (-> real? integer? real?)) (frexp (-> real? (values real? integer?))) (sign (-> real? (integer-in -1 1))) (fcmp (-> real? real? real? (integer-in -1 1)))) (require "machine.ss") ;; ----------------------------------------------------------------- ;; ;; Mathematical Constants ;; ;; The library ensures that the standard BSD mathematical constants ;; are defined. ;; The base of exponentials, e (define e 2.71828182845904523536028747135) ;; The base-2 logarithm of e, log_2(e) (define log2e 1.44269504088896340735992468100) ;; The base-10 logarithm of e, log_10(e) (define log10e 0.43429448190325182765112891892) ;; The square root of two, sqrt(2) (define sqrt2 1.41421356237309504880168872421) ;; The square root of one half, sqrt(1/2) (define sqrt1/2 0.70710678118654752440084436210) ;; The square root of three, sqrt(3) (define sqrt3 1.73205080756887729352744634151) ;; The constant pi (define pi 3.14159265358979323846264338328) ;; Pi divided by two, pi/2 (define pi/2 1.57079632679489661923132169164) ;; Pi divided by four, pi/4 (define pi/4 0.78539816339744830966156608458) ;; The square root of pi, sqrt(pi) (define sqrtpi 1.77245385090551602729816748334) ;; Two divided by the square root of pi, 2/sqrt(pi) (define 2/sqrtpi 1.12837916709551257389615890312) ;; The reciprocal of pi, 1/pi (define 1/pi 0.31830988618379067153776752675) ;; Twice the reciprocal of pi, 2/pi (define 2/pi 0.63661977236758134307553505349) ;; The natural logarithm of ten, ln(10) (define ln10 2.30258509299404568401799145468) ;; The natural logarithm of two, ln(2) (define ln2 0.69314718055994530941723212146) ;; The natural logarithm of pi, ln(pi) (define lnpi 1.14472988584940017414342735135) ;; Euler's constant, gamma (define euler 0.57721566490153286060651209008) ;; ----------------------------------------------------------------- ;; ;; Infinities and Not-a-Number ;; ;; PLT Scheme provides +inf.0 (infinity), -inf.0 (negative ;; infinity), +nan.0 (not a number) and -nan.0 (same as +nan.0) as ;; inexact numerical constants. ;; nan?: any -> boolean ;; ;; Returns true if x is equivalent to +nan.0. (define (nan? x) (eqv? x +nan.0)) ;; infinite?: any -> boolean or (-1, 1) ;; ;; Returns 1 if x is +inf.0, -1 if x is -inf.0, and false otherwise. (define (infinite? x) (if (eqv? x +inf.0) 1 (if (eqv? x -inf.0) -1 #f))) ;; finite?: real -> boolean ;; ;; Returns true of x is a finite, real number. (define (finite? x) (and (real? x) (not (nan? x)) (not (infinite? x)))) ;; ----------------------------------------------------------------- ;; ;; Elementary Functions ;; log1p: real -> number (real? for x > 1, complex for x < 1) ;; ;; Computes the value of log(1+x) is a way that is accurate for ;; small x. (define (log1p x) (let ((y (+ 1.0 x))) (- (log y) (/ (- (- y 1.0) x) y)))) ;; expm1: real -> real ;; ;; Computes the value of exp(x)-1 in a way that is accurate for ;; small x. (define (expm1 x) (if (< (abs x) ln2) ;; Compute the taylor series S = x + (1/2!) x^2 + (1/3!) x^3 + ;; ... (let ((i 1.0) (sum x) (term (/ x 1.0))) (let loop () (set! i (+ i 1.0)) (set! term (* term (/ x i))) (set! sum (+ sum term)) (if (> (abs term) (* (abs sum) double-epsilon)) (loop))) sum) (- (exp x) 1.0))) ;; hypot: real x real -> real ;; ;; Computes the value of sqrt(x^2 + y^2) in a way that avoids ;; overflow. (define (hypot x y) (let ((xabs (abs x)) (yabs (abs y)) (min 0) (max 0)) (if (< xabs yabs) (begin (set! min xabs) (set! max yabs)) (begin (set! min yabs) (set! max xabs))) (if (= min 0) max) (let ((u (/ min max))) (* max (sqrt (+ 1.0 (* u u))))))) ;; acosh: real -> real ;; ;; Computes the value of arccosh(x) (define (acosh x) (cond ((> x (/ 1.0 sqrt-double-epsilon)) (+ (log x) ln2)) ((> x 2.0) (log (- (* 2.0 x) (/ 1.0 (+ (sqrt (- (* x x) 1.0)) x))))) ((> x 1.0) (let ((t (- x 1.0))) (log1p (+ (* 2.0 t) (* t t))))) ((= x 1.0) 0.0) (else +nan.0))) ;; asinh: real -> real ;; ;; Computes the value of arcsinh(x) (define (asinh x) (let ((a (abs x)) (s (if (< x 0) -1.0 1.0))) (cond ((> a (/ 1.0 sqrt-double-epsilon)) (* s (+ (log a) ln2))) ((> a 2.0) (* s (log (+ (* 2.0 a) (/ a (sqrt (+ (* a a) 1.0))))))) ((> a sqrt-double-epsilon) (let ((a2 (* a a))) (* s (log1p (+ a (/ a2 (+ 1.0 (sqrt (+ 1.0 a2))))))))) (else x)))) ;; atanh: real -> real ;; ;; Computes the value of arctanh(x). (define (atanh x) (let ((a (abs x)) (s (if (< x 0) -1.0 1.0))) (cond ((> a 1) +nan.0) ((= a 1) (if (< x 0) -inf.0 +inf.0)) ((>= x 0.5) (* s 0.5 (log1p (/ (* 2.0 a) (- 1.0 a))))) ((> a double-epsilon) (* s 0.5 (log1p (+ (* 2.0 a) (/ (* 2.0 a a) (- 1.0 a)))))) (else x)))) ;; ldexp: real x integer -> real ;; ;; Computes the value of x * 2^e. (define (ldexp x e) (let ((p2 (expt 2.0 e))) (* x p2))) ;; frexp: real -> real x integer ;; ;; Splits the number x into its normalized fraction f and exponent ;; e, such that x = f * 2^e and 0.5 <= f < 1. (define (frexp x) (if (= x 0) (values 0.0 0) (let* ((ex (ceiling (log (/ (abs x) ln2)))) (ei (inexact->exact ex)) (f (ldexp x (- ei)))) (let loop () (if (>= (abs f) 1.0) (begin (set! ei (+ ei 1)) (set! f (/ f 2.0)) (loop)))) (let loop () (if (< (abs f) 0.5) (begin (set! ei (- ei 1)) (set! f (* f 2.0)) (loop)))) (values f ei)))) ;; ----------------------------------------------------------------- ;; Testing the Sign of Numbers ;; sign: real -> integer ;; ;; Return the sign of a real number, 1 for positive (or zero), ;; -1 for negative. (define (sign x) (if (>= x 0) 1 -1)) ;; ----------------------------------------------------------------- ;; Testing form Odd and Even Numbers ;; ;; Scheme provides even? and odd? ;; ----------------------------------------------------------------- ;; Maximimum and Minimum Functions ;; ;; Scheme provides min and max ;; ----------------------------------------------------------------- ;; Approximate Comparison of Floating Point Numbers ;; fcmp: real x real x real -> integer ;; ;; Compare two real for difference less than the specified epsilon. ;; Returns -1 if x1 < x2; 0 if x1 ~= x2; 1 if x1 > x2. (define (fcmp x1 x2 epsilon) (let* ((exponent 0) (delta 0.0) (difference (- x1 x2)) (dummy 0.0) (max (if (> (abs x1) (abs x2)) x1 x2))) (set!-values (dummy exponent) (frexp max)) (set! delta (ldexp epsilon exponent)) (if (> difference delta) 1 ; x1 > x2 (if (< difference (- delta)) -1 ; x1 < x2 0)))) ; x1 ~= x2 )