;;; Copyright (C) William D Clinger (2016). ;;; ;;; Permission is hereby granted, free of charge, to any person ;;; obtaining a copy of this software and associated documentation ;;; files (the "Software"), to deal in the Software without ;;; restriction, including without limitation the rights to use, ;;; copy, modify, merge, publish, distribute, sublicense, and/or ;;; sell copies of the Software, and to permit persons to whom the ;;; Software is furnished to do so, subject to the following ;;; conditions: ;;; ;;; The above copyright notice and this permission notice shall be ;;; included in all copies or substantial portions of the Software. ;;; ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ;;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ;;; OTHER DEALINGS IN THE SOFTWARE. ;;; References ;;; ;;; Milton Abramowitz and Irene A Stegun [editors]. ;;; Handbook of Mathematical Functions With Formulas, Graphs, and ;;; Mathematical Tables. United States Department of Commerce. ;;; National Bureau of Standards Applied Mathematics Series, 55, ;;; June 1964. Fifth Printing, August 1966, with corrections. ;;; ;;; R W Hamming. Numerical Methods for Scientists and Engineers. ;;; McGraw-Hill, 1962. ;;; ;;; Donald E Knuth. The Art of Computer Programming, Volume 2, ;;; Seminumerical Algorithms, Second Edition. Addison-Wesley, 1981. ;;; ;;; J N Newman. Approximations for the Bessel and Struve Functions. ;;; Mathematics of Computation, 43(168), October 1984, pages 551-556. ;;; I have deliberately avoided recent references, and have also ;;; avoided looking at any code or pseudocode for these or similar ;;; functions. ;;; Quick-and-dirty implementation of a draft of SRFI 144 (flonums), ;;; as specified at http://vrici.lojban.org/~cowan/temp/srfi-144.html ;;; as of 4 June 2017. ;;; ;;; FIXME: not as accurate as it should be ;;; FIXME: not as fast as it should be ;;; FIXME: assumes IEEE arithmetic or similar ;;; FIXME: assumes all inexact reals are flonums ;;; FIXME: assumes (scheme inexact) ;;; Mathematical Constants ;;; ;;; The mathematical constants are now defined in 144.constants.scm (foreign-declare "#include \"float.h\"") ;; Implementation Constants (define fl-greatest maximum-flonum) (define fl-least (foreign-value "DBL_TRUE_MIN" double)) (define fl-epsilon flonum-epsilon) (define fl-integer-exponent-zero ; arbitrary (exact (- (log fl-least 2.0) 1.0))) (define fl-integer-exponent-nan ; arbitrary (- fl-integer-exponent-zero 1)) ;;; Constructors ; Implements post-finalization note 1 (define (flonum x) (if (real? x) (inexact x) +nan.0)) (define fladjacent (flop2 'fladjacent (lambda (x y) (define (loop y) (let* ((y3 (fl+ (fl* 0.999755859375 x) (fl* 0.000244140625 y)))) (cond ((fl? x y) fl-greatest) (else x))) ((fl=? x y) x) ((flzero? x) (if (flpositive? y) fl-least (fl- fl-least))) ((fl? x y) (loop (flmax y (fl- fl-greatest) (flmin (* 2.0 x) (* 0.5 x))))) (else ; x or y is a NaN x))))) (define flcopysign (flop2 'flcopysign (lambda (x y) (if (= (flsign-bit x) (flsign-bit y)) x (fl- x))))) (define (make-flonum x n) (let ((y (expt 2.0 n))) (cond ((or (not (flonum? x)) (not (exact-integer? n))) (error "bad arguments to make-flonum" x n)) ((finite? y) (* x y)) (else (inexact (* (exact x) (expt 2 n))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Accessors (define (flinteger-fraction x) (check-flonum! 'flinteger-fraction x) (let* ((result1 (fltruncate x)) (result2 (fl- x result1))) (values result1 result2))) (define (flexponent x) (floor (fllog2 (flabs x)))) (define (flinteger-exponent x) (exact (flexponent x))) (define (flnormalized-fraction-exponent x) (define (return result1 result2) (cond ((fl=? result1 1.0) (values (fl* 0.5 result1) (+ result2 1))) (else (values result1 result2)))) (check-flonum! 'flnormalized-fraction-exponent x) (cond ((flnan? x) ; unspecified for NaN (values x 0)) ((fl? R6RS) ; defined by (rnrs arithmetic flonums) ;(define fl<=? R6RS) ; defined by (rnrs arithmetic flonums) ;(define fl>=? R6RS) ; defined by (rnrs arithmetic flonums) (define (flunordered? x y) (or (flnan? x) (flnan? y))) ;;; incompatible with (rnrs arithmetic flonums) in zero-argument case (define flmax (case-lambda (() -inf.0) ((x) x) ((x y) (fpmax x y)) ((x . rest) (fpmax (fpmax x (car rest)) (apply flmax (cdr rest)))))) ;;; incompatible with (rnrs arithmetic flonums) in zero-argument case (define flmin (case-lambda (() +inf.0) ((x) x) ((x y) (fpmin x y)) ((x . rest) (fpmin (fpmin x (car rest)) (apply flmin (cdr rest)))))) ;(define flinteger? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flzero? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flpositive? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flnegative? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flodd? R6RS) ; defined by (rnrs arithmetic flonums) ;(define fleven? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flfinite? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flinfinite? R6RS) ; defined by (rnrs arithmetic flonums) ;(define flnan? R6RS) ; defined by (rnrs arithmetic flonums) (define flnormalized? (lambda (x) (check-flonum! 'flnormalized? x) (let ((x (flabs x))) (and (flfinite? x) (fl? y x) (flhypot y x)) (else (let* ((y/x (fl/ y x)) (root (flsqrt (fl+ 1.0 (fl* y/x y/x))))) (fl* (flabs x) root))))))) ;(define flexpt R6RS) ; defined by (rnrs arithmetic flonums) ;(define fllog R6RS) ; defined by (rnrs arithmetic flonums) ;;; Returns log(x+1), as in C99 log1p. ;;; See ;;; https://stat.ethz.ch/pipermail/r-devel/2003-August/027396.html ;;; https://books.google.com/books?id=OjUyDwAAQBAJ&pg=PA290&lpg=PA290&dq=beebe+log1p&source=bl&ots=VLxmiSk1fA&sig=ACfU3U0_8tqKemomSjKW73iJ0zUO1u3p3Q&hl=en&sa=X&ved=2ahUKEwjfxZbE8LvhAhVNm-AKHWScB7w4ChDoATAAegQICRAB#v=onepage&q=beebe%20log1p&f=false ;;; for justification (define fllog1+ (flop1 'fllog1+ (lambda (x) (let ((u (fl+ 1.0 x))) (cond ((fl=? u 1.0) x) ;; gets sign of zero result correct ((fl=? u x) (fllog u)) ;; large arguments and infinities (else (fl* (fllog u) (fl/ x (fl- u 1.0))))))))) (define fllog2 (flop1 'fllog2 (lambda (x) (log x 2.0)))) (define fllog10 (flop1 'fllog10 (lambda (x) (log x 10.0)))) (define (make-fllog-base base) (check-flonum! 'make-fllog-base base) (if (fl>? base 1.0) (flop1 'procedure-created-by-make-fllog-base (lambda (x) (log x base))) (error "argument to make-fllog-base must be greater than 1.0" base))) ;;; Trigonometric functions ;(define flsin R6RS) ; defined by (rnrs arithmetic flonums) ;(define flcos R6RS) ; defined by (rnrs arithmetic flonums) ;(define fltan R6RS) ; defined by (rnrs arithmetic flonums) ;(define flasin R6RS) ; defined by (rnrs arithmetic flonums) ;(define flacos R6RS) ; defined by (rnrs arithmetic flonums) ;(define flatan R6RS) ; defined by (rnrs arithmetic flonums) (define flsinh (flop1 'flsinh (lambda (x) (cond ((not (flfinite? x)) x) ((fl