This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "OCT: A portable Lisp implementation for quad-double precision floats".
The branch, master has been updated via c239a8514ff5f1fc96d33a4c581cbaec834f6641 (commit) via 46359140b7aa3c0c4af6b3aabc7bcbb4cf248301 (commit) via 85f3e2b22f917ff35d080180ab1e2dda4476e881 (commit) from 68432cb1855605c346216788f1aa64517a96a808 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit c239a8514ff5f1fc96d33a4c581cbaec834f6641 Author: Raymond Toy toy.raymond@gmail.com Date: Thu Mar 10 22:23:50 2011 -0500
Implement elliptic integrals of the first kind.
o Add FLOAT-CONTAGION to determine the max precision of the given arguments so we can do appopriate contagion in the routines. o Add some docstrings and other documentation of the algorithms. o Add implmentation of ELLIPTIC-K and ELLIPTIC-F for the complete and incomplete elliptic integrals of the first kind, respectively.
diff --git a/qd-elliptic.lisp b/qd-elliptic.lisp index 2fadecd..63c3687 100644 --- a/qd-elliptic.lisp +++ b/qd-elliptic.lisp @@ -29,6 +29,57 @@
(declaim (inline descending-transform ascending-transform))
+;; Determine which of x and y has the higher precision and return the +;; value of the higher precision number. If both x and y are +;; rationals, just return 1f0, for a single-float value. +(defun float-contagion-2 (x y) + (etypecase x + (cl:rational + (etypecase y + (cl:rational + 1f0) + (cl:float + y) + (qd-real + y))) + (single-float + (etypecase y + ((or cl:rational single-float) + x) + ((or double-float qd-real) + y))) + (double-float + (etypecase y + ((or cl:rational single-float double-float) + x) + (qd-real + y))) + (qd-real + x))) + +;; Return a floating point (or complex) type of the highest precision +;; among all of the given arguments. +(defun float-contagion (&rest args) + ;; It would be easy if we could just add the args together and let + ;; normal contagion do the work, but we could easily introduce + ;; overflows or other errors that way. So look at each argument and + ;; determine the precision and choose the highest precision. + (let ((complexp (some #'complexp args)) + (max-type + (etypecase (reduce #'float-contagion-2 (mapcar #'realpart (if (cdr args) + args + (list (car args) 0)))) + (single-float 'single-float) + (double-float 'double-float) + (qd-real 'qd-real)))) + (if complexp + (if (eq max-type 'qd-real) + 'qd-complex + `(cl:complex ,max-type)) + max-type))) + +;;; Jacobian elliptic functions + (defun ascending-transform (u m) ;; A&S 16.14.1 ;; @@ -153,12 +204,14 @@ new-dn)))))
(defun jacobi-sn (u m) + "Compute Jacobian sn for argument u and parameter m" (let ((s (elliptic-sn-descending u m))) (if (and (realp u) (realp m)) (realpart s) s)))
(defun jacobi-dn (u m) + "Compute Jacobi dn for argument u and parameter m" ;; Use the Gauss transformation from ;; http://functions.wolfram.com/09.29.16.0013.01: ;; @@ -192,6 +245,7 @@ (+ 1 p))))
(defun jacobi-cn (u m) + "Compute Jacobi cn for argument u and parameter m" ;; Use the ascending Landen transformation, A&S 16.14.3. ;; ;; cn(u,m) = (1+sqrt(mu1))/mu * (dn(v,mu)^2-sqrt(mu1))/dn(v,mu) @@ -202,17 +256,32 @@ (/ (- (* d d) root-mu1) d))))) +;;; Elliptic Integrals +;;; +;; Translation of Jim FitzSimons' bigfloat implementation of elliptic +;; integrals from http://www.getnet.com/~cherry/elliptbf3.mac. +;; +;; The algorithms are based on B.C. Carlson's "Numerical Computation +;; of Real or Complex Elliptic Integrals". These are updated to the +;; algorithms in Journal of Computational and Applied Mathematics 118 +;; (2000) 71-85 "Reduction Theorems for Elliptic Integrands with the +;; Square Root of two quadritic factors" +;; + (defun errtol (&rest args) - ;; Compute error tolerance as sqrt(2^(-fpprec)). Not sure this is - ;; quite right, but it makes the routines more accurate as fpprec - ;; increases. + ;; Compute error tolerance as sqrt(<float-precision>). Not sure + ;; this is quite right, but it makes the routines more accurate as + ;; precision increases increases. (sqrt (reduce #'min (mapcar #'(lambda (x) (if (rationalp x) - double-float-epsilon + single-float-epsilon (epsilon x))) args))))
(defun carlson-rf (x y z) + "Compute Carlson's Rf function: + + Rf(x, y, z) = 1/2*integrate((t+x)^(-1/2)*(t+y)^(-1/2)*(t+z)^(-1/2), t, 0, inf)" (let* ((xn x) (yn y) (zn z) @@ -252,8 +321,90 @@ (* -3/44 ee2 ee3)))) (/ s (sqrt an)))))
+;; Complete elliptic integral of the first kind. This can be computed +;; from Carlson's Rf function: +;; +;; K(m) = Rf(0, 1 - m, 1) (defun elliptic-k (m) + "Complete elliptic integral of the first kind K for parameter m + + K(m) = integrate(1/sqrt(1-m*sin(x)^2), x, 0, %pi/2). + + Note: K(m) = F(%pi/2, m), where F is the (incomplete) elliptic + integral of the first kind." (cond ((= m 0) (/ (float +pi+ m) 2)) (t - (carlson-rf 0 (- 1 m) 1)))) + (let ((precision (float-contagion m))) + (carlson-rf (coerce 0 precision) (- 1 m) (coerce 1 precision)))))) + +;; Elliptic integral of the first kind. This is computed using +;; Carlson's Rf function: +;; +;; F(phi, m) = sin(phi) * Rf(cos(phi)^2, 1 - m*sin(phi)^2, 1) +(defun elliptic-f (x m) + "Incomplete Elliptic integral of the first kind: + + F(x, m) = integrate(1/sqrt(1-m*sin(phi)^2), phi, 0, x) + + Note for the complete elliptic integral, you can use elliptic-k" + (let* ((precision (float-contagion x m)) + (x (coerce x precision)) + (m (coerce m precision))) + (cond ((and (realp m) (realp x)) + (cond ((> m 1) + ;; A&S 17.4.15 + ;; + ;; F(phi|m) = 1/sqrt(m)*F(theta|1/m) + ;; + ;; with sin(theta) = sqrt(m)*sin(phi) + (/ (elliptic-f (cl:asin (* (sqrt m) (sin x))) (/ m)) + (sqrt m))) + ((< m 0) + ;; A&S 17.4.17 + (let* ((m (- m)) + (m+1 (+ 1 m)) + (root (sqrt m+1)) + (m/m+1 (/ m m+1))) + (- (/ (elliptic-f (/ (float-pi m) 2) m/m+1) + root) + (/ (elliptic-f (- (/ (float-pi x) 2) x) m/m+1) + root)))) + ((= m 0) + ;; A&S 17.4.19 + x) + ((= m 1) + ;; A&S 17.4.21 + ;; + ;; F(phi,1) = log(sec(phi)+tan(phi)) + ;; = log(tan(pi/4+pi/2)) + (log (cl:tan (+ (/ x 2) (/ (float-pi x) 4))))) + ((minusp x) + (- (elliptic-f (- x) m))) + ((> x (float-pi x)) + ;; A&S 17.4.3 + (multiple-value-bind (s x-rem) + (truncate x (float-pi x)) + (+ (* 2 s (elliptic-k m)) + (elliptic-f x-rem m)))) + ((<= x (/ (float-pi x) 2)) + (let ((sin-x (sin x)) + (cos-x (cos x)) + (k (sqrt m))) + (* sin-x + (carlson-rf (* cos-x cos-x) + (* (- 1 (* k sin-x)) + (+ 1 (* k sin-x))) + 1.0)))) + ((< x (float-pi x)) + (+ (* 2 (elliptic-k m)) + (elliptic-f (- x (float pi x)) m))))) + (t + (let ((sin-x (sin x)) + (cos-x (cos x)) + (k (sqrt m))) + (* sin-x + (carlson-rf (* cos-x cos-x) + (* (- 1 (* k sin-x)) + (+ 1 (* k sin-x))) + 1)))))))
commit 46359140b7aa3c0c4af6b3aabc7bcbb4cf248301 Author: Raymond Toy toy.raymond@gmail.com Date: Thu Mar 10 22:21:26 2011 -0500
Add documentation for EPSILON and add FLOAT-PI.
FLOAT-PI returns a value of pi that matches the precision of the argument.
diff --git a/qd-methods.lisp b/qd-methods.lisp index 6f41857..966d85f 100644 --- a/qd-methods.lisp +++ b/qd-methods.lisp @@ -1063,7 +1063,13 @@ underlying floating-point format" (frob two-arg-- cl:- sub-qd sub-d-qd sub-qd-d) (frob two-arg-* cl:* mul-qd mul-d-qd mul-qd-d) (frob two-arg-/ cl:/ div-qd nil nil)) - + +(defgeneric epsilon (m) + (:documentation +"Return an epsilon value of the same precision as the argument. It is +the smallest number x such that 1+x /= x. The argument can be +complex")) + (defmethod epsilon ((m cl:float)) (etypecase m (single-float single-float-epsilon) @@ -1082,3 +1088,23 @@ underlying floating-point format"
(defmethod epsilon ((m qd-complex)) (epsilon (realpart m))) + +(defgeneric float-pi (x) + (:documentation +"Return a floating-point value of the mathematical constant pi that is +the same precision as the argument. The argument can be complex.")) + +(defmethod float-pi ((x cl:rational)) + (float pi 1f0)) + +(defmethod float-pi ((x cl:float)) + (float pi x)) + +(defmethod float-pi ((x qd-real)) + +pi+) + +(defmethod float-pi ((z cl:complex)) + (float pi (realpart z))) + +(defmethod float-pi ((z qd-complex)) + +pi+) \ No newline at end of file
commit 85f3e2b22f917ff35d080180ab1e2dda4476e881 Author: Raymond Toy toy.raymond@gmail.com Date: Thu Mar 10 22:20:27 2011 -0500
Move inline function NEG-QD-T before first use.
diff --git a/qd.lisp b/qd.lisp index af5a779..fb3e4e1 100644 --- a/qd.lisp +++ b/qd.lisp @@ -476,11 +476,6 @@ If TARGET is given, TARGET is destructively modified to contain the result." (%store-qd-d target (+ a0 b0) 0d0 0d0 0d0) (%store-qd-d target s0 s1 s2 s3)))))))))))
-(defun neg-qd (a &optional (target #+oct-array (%make-qd-d 0d0 0d0 0d0 0d0))) - "Return the negative of the %QUAD-DOUBLE number A. -If TARGET is given, TARGET is destructively modified to contain the result." - (neg-qd-t a target)) - (defun neg-qd-t (a target) (declare (type %quad-double a #+oct-array target) #+(and cmu (not oct-array)) (ignore target)) @@ -489,6 +484,13 @@ If TARGET is given, TARGET is destructively modified to contain the result." (declare (double-float a0 a1 a2 a3)) (%store-qd-d target (cl:- a0) (cl:- a1) (cl:- a2) (cl:- a3))))
+(defun neg-qd (a &optional (target #+oct-array (%make-qd-d 0d0 0d0 0d0 0d0))) + "Return the negative of the %QUAD-DOUBLE number A. +If TARGET is given, TARGET is destructively modified to contain the result." + (neg-qd-t a target)) + + + (defun sub-qd (a b &optional (target #+oct-array (%make-qd-d 0d0 0d0 0d0 0d0))) "Return the difference between the %QUAD-DOUBLE numbers A and B. If TARGET is given, TARGET is destructively modified to contain the result."
-----------------------------------------------------------------------
Summary of changes: qd-elliptic.lisp | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- qd-methods.lisp | 28 +++++++++- qd.lisp | 12 ++-- 3 files changed, 190 insertions(+), 11 deletions(-)
hooks/post-receive