added oct package for long-long arith
[CommonLispStat.git] / external / oct / qd-fun.lisp
blob2cd9e0f3a17e7ab0306b6d947cede6e7e822feeb
1 ;;;; -*- Mode: lisp -*-
2 ;;;;
3 ;;;; Copyright (c) 2007 Raymond Toy
4 ;;;;
5 ;;;; Permission is hereby granted, free of charge, to any person
6 ;;;; obtaining a copy of this software and associated documentation
7 ;;;; files (the "Software"), to deal in the Software without
8 ;;;; restriction, including without limitation the rights to use,
9 ;;;; copy, modify, merge, publish, distribute, sublicense, and/or sell
10 ;;;; copies of the Software, and to permit persons to whom the
11 ;;;; Software is furnished to do so, subject to the following
12 ;;;; conditions:
13 ;;;;
14 ;;;; The above copyright notice and this permission notice shall be
15 ;;;; included in all copies or substantial portions of the Software.
16 ;;;;
17 ;;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 ;;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 ;;;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 ;;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 ;;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 ;;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 ;;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 ;;;; OTHER DEALINGS IN THE SOFTWARE.
26 ;;; Basic special functions operating on %quad-double numbers. This
27 ;;; includes sqrt, rounding to the nearest integer, floor, exp, log,
28 ;;; log1p, sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh,
29 ;;; asinh, acosh, atanh, and random.
30 ;;;
31 ;;; These special functions only work on the main domains where the
32 ;;; argument is real and the result is real. Behavior is undefined if
33 ;;; this doesn't hold.
35 (in-package #:qdi)
37 #+cmu
38 (declaim (maybe-inline sqrt-qd))
39 (defun sqrt-qd (a)
40 "Square root of the (non-negative) quad-float"
41 (declare (type %quad-double a)
42 (optimize (speed 3) (space 0)))
43 ;; Perform the following Newton iteration:
45 ;; x' = x + (1 - a * x^2) * x / 2
47 ;; which converges to 1/sqrt(a).
49 ;; However, there appear to be round-off errors when x is either
50 ;; very large or very small. So let x = f*2^(2*k). Then sqrt(x) =
51 ;; 2^k*sqrt(f), and sqrt(f) doesn't have round-off problems.
52 (when (zerop-qd a)
53 (return-from sqrt-qd a))
54 #+cmu
55 (when (float-infinity-p (qd-0 a))
56 (return-from sqrt-qd a))
58 (let* ((k (logandc2 (logb-finite (qd-0 a)) 1))
59 (new-a (scale-float-qd a (- k))))
60 (assert (evenp k))
61 (let* ((r (make-qd-d (cl:/ (sqrt (the (double-float (0d0))
62 (qd-0 new-a))))))
63 (half 0.5d0)
64 (h (mul-qd-d new-a half)))
65 (declare (type %quad-double r))
66 ;; Since we start with double-float precision, three more
67 ;; iterations should give us full accuracy.
68 (dotimes (k 3)
69 (setf r (add-qd r (mul-qd r (sub-d-qd half (mul-qd h (sqr-qd r)))))))
70 (scale-float-qd (mul-qd r new-a) (ash k -1)))))
72 (defun logb-finite (x)
73 "Same as logb but X is not infinity and non-zero and not a NaN, so
74 that we can always return an integer"
75 (declare (type cl:float x))
76 (multiple-value-bind (signif expon sign)
77 (cl:decode-float x)
78 (declare (ignore signif sign))
79 ;; decode-float is almost right, except that the exponent
80 ;; is off by one
81 (1- expon)))
83 (defun hypot-aux-qd (x y)
84 (declare (type %quad-double x y))
85 (let ((k (- (logb-finite (max (cl:abs (qd-0 x))
86 (cl:abs (qd-0 y)))))))
87 (values (add-qd (sqr-qd (scale-float-qd x k))
88 (sqr-qd (scale-float-qd y k)))
89 (- k))))
91 (defun hypot-qd (x y)
92 "sqrt(x^2+y^2) computed carefully without unnecessary overflow"
93 (multiple-value-bind (abs^2 rho)
94 (hypot-aux-qd x y)
95 (scale-float-qd (sqrt-qd abs^2) rho)))
97 (defun nint-qd (a)
98 "Round the quad-float to the nearest integer, which is returned as a
99 quad-float"
100 (let ((x0 (fround (qd-0 a)))
101 (x1 0d0)
102 (x2 0d0)
103 (x3 0d0))
104 (cond ((= x0 (qd-0 a))
105 ;; First double is already an integer
106 (setf x1 (fround (qd-1 a)))
107 (cond ((= x1 (qd-1 a))
108 ;; Second is an integer
109 (setf x2 (fround (qd-2 a)))
110 (cond ((= x2 (qd-2 a))
111 ;; Third is an integer
112 (setf x3 (fround (qd-3 a))))
114 (when (and (zerop (abs (cl:- x2 (qd-2 a))))
115 (minusp (qd-3 a)))
116 (decf x2)))))
118 (when (and (zerop (abs (cl:- x1 (qd-1 a))))
119 (minusp (qd-2 a)))
120 (decf x1)))))
122 (when (and (zerop (abs (cl:- x0 (qd-0 a))))
123 (minusp (qd-1 a)))
124 (decf x0))))
125 (multiple-value-bind (s0 s1 s2 s3)
126 (renorm-4 x0 x1 x2 x3)
127 (make-qd-d s0 s1 s2 s3))))
129 (defun ffloor-qd (a)
130 "The floor of A, returned as a quad-float"
131 (let ((x0 (ffloor (qd-0 a)))
132 (x1 0d0)
133 (x2 0d0)
134 (x3 0d0))
135 (cond ((= x0 (qd-0 a))
136 (setf x1 (ffloor (qd-1 a)))
137 (when (= x1 (qd-1 a))
138 (setf x2 (ffloor (qd-2 a)))
139 (when (= x2 (qd-2 a))
140 (setf x3 (ffloor (qd-3 a)))))
141 (make-qd-d x0 x1 x2 x3))
143 (%make-qd-d x0 x1 x2 x3)))))
146 (defun exp-qd/reduce (a)
147 ;; Strategy: Reduce the size of x by noting that
149 ;; exp(k*r+m) = exp(m) * exp(r)^k
151 ;; Thus, by choosing m to be a multiple of log(2) closest to x, we
152 ;; can make |kr| < log(2)/2 = 0.3466. Now we can set k = 256, so
153 ;; that |r| <= 0.00136.
155 ;; Then
157 ;; exp(x) = exp(k*r+s*log(2)) = 2^s*(exp(r))^256
159 ;; We can use Taylor series to evaluate exp(r).
161 (let* ((k 256)
162 (z (truncate (qd-0 (nint-qd (div-qd a +qd-log2+)))))
163 (r1 (sub-qd a (mul-qd-d +qd-log2+ (float z 1d0))))
164 ;; r as above
165 (r (div-qd-d (sub-qd a (mul-qd-d +qd-log2+ (float z 1d0)))
166 (float k 1d0)))
167 ;; For Taylor series. p = r^2/2, the first term
168 (p (div-qd-d (sqr-qd r) 2d0))
169 ;; s = 1+r+p, the sum of the first 3 terms
170 (s (add-qd-d (add-qd r p) 1d0))
171 ;; Denominator of term
172 (m 2d0))
173 ;; Taylor series until the term is small enough.
175 ;; Note that exp(x) = sinh(x) + sqrt(1+sinh(x)^2). The Taylor
176 ;; series for sinh has half as many terms as for exp, so it should
177 ;; be less work to compute sinh. Then a few additional operations
178 ;; and a square root gives us exp.
179 (loop
180 (incf m)
181 (setf p (mul-qd p r))
182 (setf p (div-qd-d p m))
183 (setf s (add-qd s p))
184 (unless (> (abs (qd-0 p)) +qd-eps+)
185 (return)))
187 (setf r (npow s k))
188 (setf r (scale-float-qd r z))
191 (defun expm1-qd/duplication (a)
192 (declare (type %quad-double a))
193 ;; Brent gives expm1(2*x) = expm1(x)*(2+expm1(x))
195 ;; Hence
197 ;; expm1(x) = expm1(x/2)*(2+expm1(x/2))
199 ;; Keep applying this formula until x is small enough. Then use
200 ;; Taylor series to compute expm1(x).
201 (cond ((< (abs (qd-0 a)) .0001d0)
202 ;; What is the right threshold?
204 ;; Taylor series for exp(x)-1
205 ;; = x+x^2/2!+x^3/3!+x^4/4!+...
206 ;; = x*(1+x/2!+x^2/3!+x^3/4!+...)
207 (let ((sum +qd-one+)
208 (term +qd-one+))
209 (dotimes (k 28)
210 (setf term (div-qd-d (mul-qd term a) (float (cl:+ k 2) 1d0)))
211 (setf sum (add-qd sum term)))
212 (mul-qd a sum)))
214 (let ((d (expm1-qd/duplication (scale-float-qd a -1))))
215 (mul-qd d (add-qd-d d 2d0))))))
217 (defun expm1-qd (a)
218 "exp(a) - 1, done accurately"
219 (declare (type %quad-double a))
220 #+cmu
221 (when (float-infinity-p (qd-0 a))
222 (return-from expm1-qd
223 (if (minusp (float-sign (qd-0 a)))
224 +qd-zero+
225 a)))
226 (expm1-qd/duplication a))
228 (defun exp-qd (a)
229 "exp(a)"
230 (declare (type %quad-double a))
231 ;; Should we try to be more accurate than just 709?
232 (when (< (qd-0 a) (log least-positive-normalized-double-float))
233 (return-from exp-qd +qd-zero+))
235 (when (> (qd-0 a) (log most-positive-double-float))
236 #-cmu
237 (error 'floating-point-overflow
238 :operation 'exp
239 :operands (list a))
240 #+cmu
241 (return-from exp-qd (%make-qd-d (/ 1d0 0d0) 0d0 0d0 0d0)))
243 (when (zerop-qd a)
244 (return-from exp-qd +qd-one+))
246 ;; Default for now is exp-qd/reduce
247 (exp-qd/reduce a))
249 (defun log-qd/halley (a)
250 (declare (type %quad-double a))
251 ;; Halley iteration:
253 ;; x' = x - 2*(exp(x)-a)/(exp(x)+a)
255 ;; But the above has problems if a is near
256 ;; most-positive-double-float. Rearrange the computation:
258 ;; x' = x - 2*(exp(x)/a-1)/(exp(x)/a+1)
260 ;; I think this works better, but it's also probably a little bit
261 ;; more expensive because each iteration has two divisions.
262 (let ((x (make-qd-d (log (qd-0 a)))))
263 (flet ((iter (est)
264 (let ((exp (div-qd (exp-qd est)
265 a)))
266 (sub-qd est
267 (scale-float-qd
268 (div-qd (sub-qd-d exp 1d0)
269 (add-qd-d exp 1d0))
270 1)))))
271 ;; Two iterations should be enough
272 (setf x (iter x))
273 (setf x (iter x))
274 x)))
277 (defun log1p-qd/duplication (x)
278 (declare (type %quad-double x)
279 (optimize (speed 3)))
280 ;; Brent gives the following duplication formula for log1p(x) =
281 ;; log(1+x):
283 ;; log1p(x) = 2*log1p(x/(1+sqrt(1+x)))
285 ;; So we apply the duplication formula until x is small enough, and
286 ;; then use the series
288 ;; log(1+x) = 2*sum((x/(2+x))^(2*k+1)/(2*k+1),k,0,inf)
290 ;; Currently "small enough" means x < 0.005. What is the right
291 ;; cutoff?
292 (cond ((> (abs (qd-0 x)) .005d0)
293 ;; log1p(x) = 2*log1p(x/(1+sqrt(1+x)))
294 (mul-qd-d (log1p-qd/duplication
295 (div-qd x
296 (add-d-qd 1d0
297 (sqrt-qd (add-d-qd 1d0 x)))))
298 2d0))
300 ;; Use the series
301 (let* ((term (div-qd x (add-qd-d x 2d0)))
302 (mult (sqr-qd term))
303 (sum term))
304 (loop for k of-type double-float from 3d0 by 2d0
305 while (> (abs (qd-0 term)) +qd-eps+)
307 (setf term (mul-qd term mult))
308 (setf sum (add-qd sum (div-qd-d term k))))
309 (mul-qd-d sum 2d0)))))
311 (defun log1p-qd (x)
312 "log1p(x) = log(1+x), done more accurately than just evaluating
313 log(1+x)"
314 (declare (type %quad-double x))
315 #+cmu
316 (when (float-infinity-p (qd-0 x))
318 (log1p-qd/duplication x))
320 (defun log-qd (a)
321 "Log(a)"
322 (declare (type %quad-double a))
323 (cond ((onep-qd a)
324 +qd-zero+)
325 ((and (zerop-qd a)
326 (plusp (float-sign (qd-0 a))))
327 (%make-qd-d (/ -1d0 (qd-0 a)) 0d0 0d0 0d0))
328 #+cmu
329 ((float-infinity-p (qd-0 a))
331 ((minusp (float-sign (qd-0 a)))
332 (error "log of negative"))
334 ;; Default is Halley's method
335 (log-qd/halley a))))
338 ;; sin(a) and cos(a) using Taylor series
340 ;; Assumes |a| <= pi/2048
341 (defun sincos-taylor (a)
342 (declare (type %quad-double a))
343 (let ((thresh (cl:* +qd-eps+ (abs (qd-0 a)))))
344 (when (zerop-qd a)
345 (return-from sincos-taylor
346 (values +qd-zero+
347 +qd-one+)))
348 (let* ((x (neg-qd (sqr-qd a)))
349 (s a)
350 (p a)
351 (m 1d0))
352 (loop
353 (setf p (mul-qd p x))
354 (incf m 2)
355 (setf p (div-qd-d p (cl:* m (cl:1- m))))
356 (setf s (add-qd s p))
357 ;;(format t "p = ~A~%" (qd-0 p))
358 (when (<= (abs (qd-0 p)) thresh)
359 (return)))
360 ;; cos(c) = sqrt(1-sin(c)^2). This seems to work ok, even
361 ;; though I would have expected some round-off errors in
362 ;; computing this. sqrt(1-x^2) is normally better computed as
363 ;; sqrt(1-x)*sqrt(1+x) for small x.
364 (values s (sqrt-qd (add-qd-d (neg-qd (sqr-qd s)) 1d0))))))
366 (defun drem-qd (a b)
367 (declare (type %quad-double a b))
368 (let ((n (nint-qd (div-qd a b))))
369 (sub-qd a (mul-qd n b))))
371 (defun divrem-qd (a b)
372 (declare (type %quad-double a b))
373 (let ((n (nint-qd (div-qd a b))))
374 (values n (sub-qd a (mul-qd n b)))))
376 (defun sin-qd (a)
377 "Sin(a)"
378 (declare (type %quad-double a))
379 ;; To compute sin(x), choose integers a, b so that
381 ;; x = s + a * (pi/2) + b*(pi/1024)
383 ;; with |x| <= pi/2048. Using a precomputed table of sin(k*pi/1024)
384 ;; and cos(k*pi/1024), we can compute sin(x) from sin(s) and cos(s).
386 ;; sin(x) = sin(s+k*(pi/1024) + j*pi/2)
387 ;; = sin(s+k*(pi/1024))*cos(j*pi/2)
388 ;; + cos(s+k*(pi/1024))*sin(j*pi/2)
390 ;; sin(s+k*pi/1024) = sin(s)*cos(k*pi/1024)
391 ;; + cos(s)*sin(k*pi/1024)
393 ;; cos(s+k*pi/1024) = cos(s)*cos(k*pi/1024)
394 ;; - sin(s)*sin(k*pi/1024)
395 (when (zerop-qd a)
396 (return-from sin-qd a))
398 ;; Reduce modulo 2*pi
399 (let ((r (drem-qd a +qd-2pi+)))
400 ;; Now reduce by pi/2 and then by pi/1024 so that we obtain
401 ;; numbers a, b, t
402 (multiple-value-bind (j tmp)
403 (divrem-qd r +qd-pi/2+)
404 (let* ((j (truncate (qd-0 j)))
405 (abs-j (abs j)))
406 (multiple-value-bind (k tmp)
407 (divrem-qd tmp +qd-pi/1024+)
408 (let* ((k (truncate (qd-0 k)))
409 (abs-k (abs k)))
410 (assert (<= abs-j 2))
411 (assert (<= abs-k 256))
412 ;; Compute sin(s) and cos(s)
413 (multiple-value-bind (sin-t cos-t)
414 (sincos-taylor tmp)
415 (multiple-value-bind (s c)
416 (cond ((zerop abs-k)
417 (values sin-t cos-t))
419 ;; Compute sin(s+k*pi/1024), cos(s+k*pi/1024)
420 (let ((u (aref +qd-cos-table+ (cl:1- abs-k)))
421 (v (aref +qd-sin-table+ (cl:1- abs-k))))
422 (cond ((plusp k)
423 ;; sin(s) * cos(k*pi/1024)
424 ;; + cos(s) * sin(k*pi/1024)
426 ;; cos(s) * cos(k*pi/1024)
427 ;; - sin(s) * sin(k*pi/1024)
428 (values (add-qd (mul-qd u sin-t)
429 (mul-qd v cos-t))
430 (sub-qd (mul-qd u cos-t)
431 (mul-qd v sin-t))))
433 ;; sin(s) * cos(k*pi/1024)
434 ;; - cos(s) * sin(|k|*pi/1024)
436 ;; cos(s) * cos(k*pi/1024)
437 ;; + sin(s) * sin(|k|*pi/1024)
438 (values (sub-qd (mul-qd u sin-t)
439 (mul-qd v cos-t))
440 (add-qd (mul-qd u cos-t)
441 (mul-qd v sin-t))))))))
442 ;;(format t "s = ~/qd::qd-format/~%" s)
443 ;;(format t "c = ~/qd::qd-format/~%" c)
444 ;; sin(x) = sin(s+k*pi/1024) * cos(j*pi/2)
445 ;; + cos(s+k*pi/1024) * sin(j*pi/2)
446 (cond ((zerop abs-j)
447 ;; cos(j*pi/2) = 1, sin(j*pi/2) = 0
449 ((= j 1)
450 ;; cos(j*pi/2) = 0, sin(j*pi/2) = 1
452 ((= j -1)
453 ;; cos(j*pi/2) = 0, sin(j*pi/2) = -1
454 (neg-qd c))
456 ;; cos(j*pi/2) = -1, sin(j*pi/2) = 0
457 (neg-qd s)))))))))))
459 (defun cos-qd (a)
460 "Cos(a)"
461 ;; Just like sin-qd, but for cos.
462 (declare (type %quad-double a))
463 ;; To compute sin(x), choose integers a, b so that
465 ;; x = s + a * (pi/2) + b*(pi/1024)
467 ;; with |x| <= pi/2048. Using a precomputed table of sin(k*pi/1024)
468 ;; and cos(k*pi/1024), we can compute sin(x) from sin(s) and cos(s).
470 ;; sin(x) = sin(s+k*(pi/1024) + j*pi/2)
471 ;; = sin(s+k*(pi/1024))*cos(j*pi/2)
472 ;; + cos(s+k*(pi/1024))*sin(j*pi/2)
474 ;; sin(s+k*pi/1024) = sin(s)*cos(k*pi/1024)
475 ;; + cos(s)*sin(k*pi/1024)
477 ;; cos(s+k*pi/1024) = cos(s)*cos(k*pi/1024)
478 ;; - sin(s)*sin(k*pi/1024)
479 (when (zerop-qd a)
480 (return-from cos-qd +qd-one+))
482 ;; Reduce modulo 2*pi
483 (let ((r (drem-qd a +qd-2pi+)))
484 ;; Now reduce by pi/2 and then by pi/1024 so that we obtain
485 ;; numbers a, b, t
486 (multiple-value-bind (j tmp)
487 (divrem-qd r +qd-pi/2+)
488 (let* ((j (truncate (qd-0 j)))
489 (abs-j (abs j)))
490 (multiple-value-bind (k tmp)
491 (divrem-qd tmp +qd-pi/1024+)
492 (let* ((k (truncate (qd-0 k)))
493 (abs-k (abs k)))
494 (assert (<= abs-j 2))
495 (assert (<= abs-k 256))
496 ;; Compute sin(s) and cos(s)
497 (multiple-value-bind (sin-t cos-t)
498 (sincos-taylor tmp)
499 (multiple-value-bind (s c)
500 (cond ((zerop abs-k)
501 (values sin-t cos-t))
503 ;; Compute sin(s+k*pi/1024), cos(s+k*pi/1024)
504 (let ((u (aref +qd-cos-table+ (cl:1- abs-k)))
505 (v (aref +qd-sin-table+ (cl:1- abs-k))))
506 (cond ((plusp k)
507 ;; sin(s) * cos(k*pi/1024)
508 ;; + cos(s) * sin(k*pi/1024)
510 ;; cos(s) * cos(k*pi/1024)
511 ;; - sin(s) * sin(k*pi/1024)
512 (values (add-qd (mul-qd u sin-t)
513 (mul-qd v cos-t))
514 (sub-qd (mul-qd u cos-t)
515 (mul-qd v sin-t))))
517 ;; sin(s) * cos(k*pi/1024)
518 ;; - cos(s) * sin(|k|*pi/1024)
520 ;; cos(s) * cos(k*pi/1024)
521 ;; + sin(s) * sin(|k|*pi/1024)
522 (values (sub-qd (mul-qd u sin-t)
523 (mul-qd v cos-t))
524 (add-qd (mul-qd u cos-t)
525 (mul-qd v sin-t))))))))
526 #+nil
527 (progn
528 (format t "s = ~/qd::qd-format/~%" s)
529 (format t "c = ~/qd::qd-format/~%" c))
530 ;; sin(x) = sin(s+k*pi/1024) * cos(j*pi/2)
531 ;; + cos(s+k*pi/1024) * sin(j*pi/2)
532 (cond ((zerop abs-j)
533 ;; cos(j*pi/2) = 1, sin(j*pi/2) = 0
535 ((= j 1)
536 ;; cos(j*pi/2) = 0, sin(j*pi/2) = 1
537 (neg-qd s))
538 ((= j -1)
539 ;; cos(j*pi/2) = 0, sin(j*pi/2) = -1
542 ;; cos(j*pi/2) = -1, sin(j*pi/2) = 0
543 (neg-qd c)))))))))))
545 ;; Compute sin and cos of a
546 (defun sincos-qd (a)
547 (declare (type %quad-double a))
548 (when (zerop-qd a)
549 (return-from sincos-qd
550 (values +qd-zero+
551 +qd-one+)))
553 ;; Reduce modulo 2*pi
554 (let ((r (drem-qd a +qd-2pi+)))
555 ;; Now reduce by pi/2 and then by pi/1024 so that we obtain
556 ;; numbers a, b, t
557 (multiple-value-bind (j tmp)
558 (divrem-qd r +qd-pi/2+)
559 (let* ((j (truncate (qd-0 j)))
560 (abs-j (abs j)))
561 (multiple-value-bind (k tmp)
562 (divrem-qd tmp +qd-pi/1024+)
563 (let* ((k (truncate (qd-0 k)))
564 (abs-k (abs k)))
565 (assert (<= abs-j 2))
566 (assert (<= abs-k 256))
567 ;; Compute sin(s) and cos(s)
568 (multiple-value-bind (sin-t cos-t)
569 (sincos-taylor tmp)
570 (multiple-value-bind (s c)
571 (cond ((zerop abs-k)
572 (values sin-t cos-t))
574 ;; Compute sin(s+k*pi/1024), cos(s+k*pi/1024)
575 (let ((u (aref +qd-cos-table+ (cl:1- abs-k)))
576 (v (aref +qd-sin-table+ (cl:1- abs-k))))
577 (cond ((plusp k)
578 ;; sin(s) * cos(k*pi/1024)
579 ;; + cos(s) * sin(k*pi/1024)
581 ;; cos(s) * cos(k*pi/1024)
582 ;; - sin(s) * sin(k*pi/1024)
583 (values (add-qd (mul-qd u sin-t)
584 (mul-qd v cos-t))
585 (sub-qd (mul-qd u cos-t)
586 (mul-qd v sin-t))))
588 ;; sin(s) * cos(k*pi/1024)
589 ;; - cos(s) * sin(|k|*pi/1024)
591 ;; cos(s) * cos(k*pi/1024)
592 ;; + sin(s) * sin(|k|*pi/1024)
593 (values (sub-qd (mul-qd u sin-t)
594 (mul-qd v cos-t))
595 (add-qd (mul-qd u cos-t)
596 (mul-qd v sin-t))))))))
597 #+nil
598 (progn
599 (format t "s = ~/qd::qd-format/~%" s)
600 (format t "c = ~/qd::qd-format/~%" c))
601 ;; sin(x) = sin(s+k*pi/1024) * cos(j*pi/2)
602 ;; + cos(s+k*pi/1024) * sin(j*pi/2)
603 (cond ((zerop abs-j)
604 ;; cos(j*pi/2) = 1, sin(j*pi/2) = 0
605 (values s c))
606 ((= j 1)
607 ;; cos(j*pi/2) = 0, sin(j*pi/2) = 1
608 (values c (neg-qd s)))
609 ((= j -1)
610 ;; cos(j*pi/2) = 0, sin(j*pi/2) = -1
611 (values (neg-qd c) s))
613 ;; cos(j*pi/2) = -1, sin(j*pi/2) = 0
614 (values (neg-qd s)
615 (neg-qd c))))))))))))
618 (defun atan2-qd/newton (y x)
619 (declare (type %quad-double y x)
620 #+nil
621 (optimize (speed 3) (space 0)))
622 ;; Instead of using Taylor series to compute atan, we instead use
623 ;; Newton's iteration to solve the equation
625 ;; sin(z) = y/r or cos(z) = x/r
627 ;; where r = sqrt(x^2+y^2)
629 ;; The iteration is
631 ;; z' = z + (y - sin(z))/cos(z) (for sin)
632 ;; z' = z + (x - cos(z))/sin(z) (for cos)
634 ;; Here, x and y are normalized so that x^2 + y^2 = 1.
636 ;; If |x| > |y|, then the first iteration is used since the
637 ;; denominator is larger. Otherwise the second is used.
638 (cond ((zerop-qd x)
639 ;; x = 0
640 (cond ((zerop-qd y)
641 ;; Both x and y are zero. Use the signs of x and y to
642 ;; determine the result
643 (error "atan2(0,0)"))
645 ;; x = 0, but y is not. Use the sign of y.
646 (return-from atan2-qd/newton
647 (cond ((plusp (float-sign (qd-0 y)))
648 +qd-pi/2+)
650 (neg-qd +qd-pi/2+)))))))
651 ((zerop-qd y)
652 ;; y = 0.
653 (return-from atan2-qd/newton
654 ;; Use the sign of x and y to figure out the result.
655 (cond ((plusp (float-sign (qd-0 x)))
656 +qd-zero+)
657 ((plusp (float-sign (qd-0 y)))
658 +qd-pi+)
660 (neg-qd +qd-pi+))))))
662 (when (qd-= x y)
663 (return-from atan2-qd/newton
664 (if (plusp-qd y)
665 +qd-pi/4+
666 +qd-3pi/4+)))
668 (when (qd-= x (neg-qd y))
669 (return-from atan2-qd/newton
670 (if (plusp-qd y)
671 +qd-3pi/4+
672 (neg-qd +qd-pi/4+))))
674 (let* ((r (hypot-qd x y))
675 (xx (div-qd x r))
676 (yy (div-qd y r)))
677 #+nil
678 (progn
679 (format t "r = ~/qdi::qd-format/~%" r)
680 (format t "xx = ~/qdi::qd-format/~%" xx)
681 (format t "yy = ~/qdi::qd-format/~%" yy))
683 ;; Compute double-precision approximation to atan
684 (let ((z (make-qd-d (atan (qd-0 y) (qd-0 x))))
685 (sinz +qd-zero+)
686 (cosz +qd-zero+))
687 (cond ((> (abs (qd-0 xx))
688 (abs (qd-0 yy)))
689 ;; Newton iteration z' = z + (y - sin(z))/cos(z)
690 (dotimes (k 3)
691 (multiple-value-setq (sinz cosz) (sincos-qd z))
692 (setf z (add-qd z (div-qd (sub-qd yy sinz)
693 cosz)))))
695 ;; Newton iteration z' = z - (x - cos(z))/sin(z)
696 (dotimes (k 3)
697 (multiple-value-setq (sinz cosz) (sincos-qd z))
698 (setf z (sub-qd z (div-qd (sub-qd xx cosz)
699 sinz))))))
700 z)))
702 (defun atan-qd/newton (y)
703 (declare (type %quad-double y)
704 #+nil (optimize (speed 3) (space 0)))
705 (atan2-qd/newton y +qd-one+))
707 (defun atan2-qd (y x)
708 "atan2(y, x) = atan(y/x), but carefully handling the quadrant"
709 (declare (type %quad-double y x))
710 (atan2-qd/newton y x))
712 (defun atan-qd (y)
713 "Atan4b*(y)"
714 (declare (type %quad-double y))
715 (atan-qd/newton y))
717 (defun asin-qd (a)
718 "Asin(a)"
719 (declare (type %quad-double a))
720 (atan2-qd a (sqrt-qd (sub-d-qd 1d0
721 (sqr-qd a)))))
723 (defun acos-qd (a)
724 "Acos(a)"
725 (declare (type %quad-double a))
726 (atan2-qd (sqrt-qd (sub-d-qd 1d0
727 (sqr-qd a)))
731 (defun tan-qd/sincos (r)
732 (declare (type %quad-double r))
733 (multiple-value-bind (s c)
734 (sincos-qd r)
735 ;; What to do, what do? If C is zero, we get divide by zero
736 ;; error. We could return infinity, but quad-double stuff doesn't
737 ;; handle infinities very well.
738 (div-qd s c)))
740 (defun tan-qd (r)
741 "Tan(r)"
742 (declare (type %quad-double r))
743 (if (zerop r)
745 (tan-qd/sincos r)))
748 (defun sinh-qd (a)
749 "Sinh(a)"
750 (declare (type %quad-double a))
751 ;; Hart et al. suggests sinh(x) = 1/2*(D(x) + D(x)/(D(x)+1))
752 ;; where D(x) = exp(x) - 1. This helps for x near 0.
753 (cond ((zerop a)
755 #+cmu
756 ((float-infinity-p (qd-0 a))
759 (let ((d (expm1-qd a)))
760 #+cmu
761 (when (float-infinity-p (qd-0 d))
762 (return-from sinh-qd d))
763 (scale-float-qd (add-qd d
764 (div-qd d (add-qd-d d 1d0)))
765 -1)))))
767 (defun cosh-qd (a)
768 "Cosh(a)"
769 (declare (type %quad-double a))
770 ;; cosh(x) = 1/2*(exp(x)+exp(-x))
771 (let ((e (exp-qd a)))
772 #+cmu
773 (when (float-infinity-p (qd-0 e))
774 (return-from cosh-qd e))
775 (scale-float-qd (add-qd e (div-qd +qd-one+ e))
776 -1)))
778 (defun tanh-qd (a)
779 "Tanh(a)"
780 (declare (type %quad-double a))
781 ;; Hart et al. suggests tanh(x) = D(2*x)/(2+D(2*x))
782 (cond ((zerop a)
784 ((> (abs (qd-0 a)) (/ (+ (log most-positive-double-float)
785 (log 2d0))
786 4d0))
787 ;; For this range of A, we know the answer is +/- 1.
789 ;; However, we could do better if we wanted. Assume x > 0
790 ;; and very large.
792 ;; tanh(x) = sinh(x)/cosh(x)
793 ;; = (1-exp(-2*x))/(1+exp(-2*x))
794 ;; = 1 - 2*exp(-2*x)/(1+exp(-2*x))
796 ;; So tanh(x) is 1 if the other term is small enough, say,
797 ;; eps. So for x large enough we can compute tanh(x) very
798 ;; accurately, thanks to how quad-double addition works.
799 ;; (The first component is, basically 1d0, and the second is
800 ;; some very small double-float.)
801 #+nil
802 (let* ((e (exp (* -2 a)))
803 (res (- 1 (/ (* 2 e) (1+ e)))))
804 (if (minusp (float-sign (qd-0 a)))
805 (neg-qd res)
806 res))
807 (make-qd-d (float-sign (qd-0 a))))
809 (let* ((a2 (mul-qd-d a 2d0))
810 (d (expm1-qd a2)))
811 (div-qd d (add-qd-d d 2d0))))))
813 (defun asinh-qd (a)
814 "Asinh(a)"
815 (declare (type %quad-double a))
816 ;; asinh(x) = log(x + sqrt(1+x^2))
818 ;; But this doesn't work well when x is small.
820 ;; log(x + sqrt(1+x^2)) = log(sqrt(1+x^2)*(1+x/sqrt(1+x^2)))
821 ;; = log(sqrt(1+x^2)) + log(1+x/sqrt(1+x^2))
822 ;; = 1/2*log(1+x^2) + log(1+x/sqrt(1+x^2))
824 ;; However that doesn't work well when x is large because x^2
825 ;; overflows.
827 ;; log(x + sqrt(1+x^2)) = log(x + x*sqrt(1+1/x^2))
828 ;; = log(x) + log(1+sqrt(1+1/x^2))
829 ;; = log(x) + log1p(sqrt(1+1/x^2))
830 #+nil
831 (log-qd (add-qd a
832 (sqrt-qd (add-qd-d (sqr-qd a)
833 1d0))))
834 (if (< (abs (qd-0 a)) (sqrt most-positive-double-float))
835 (let ((a^2 (sqr-qd a)))
836 (add-qd (scale-float-qd (log1p-qd a^2) -1)
837 (log1p-qd (div-qd a
838 (sqrt-qd (add-qd-d a^2 1d0))))))
839 (if (minusp-qd a)
840 (neg-qd (asinh-qd (neg-qd a)))
841 (let ((1/a (div-qd (make-qd-d 1d0) a)))
842 (+ (log-qd a)
843 (log1p-qd (sqrt-qd (add-qd-d (sqr-qd 1/a) 1d0))))))))
845 (defun asinh-qd (a)
846 "Asinh(a)"
847 (declare (type %quad-double a))
848 ;; asinh(x) = log(x + sqrt(1+x^2))
850 ;; But this doesn't work well when x is small.
852 ;; log(x + sqrt(1+x^2)) = log(sqrt(1+x^2)*(1+x/sqrt(1+x^2)))
853 ;; = log(sqrt(1+x^2)) + log(1+x/sqrt(1+x^2))
854 ;; = 1/2*log(1+x^2) + log(1+x/sqrt(1+x^2))
856 ;; However that doesn't work well when x is large because x^2
857 ;; overflows.
859 ;; log(x + sqrt(1+x^2)) = log(x + x*sqrt(1+1/x^2))
860 ;; = log(x) + log(1+sqrt(1+1/x^2))
861 ;; = log(x) + log1p(sqrt(1+1/x^2))
862 #+nil
863 (log-qd (add-qd a
864 (sqrt-qd (add-qd-d (sqr-qd a)
865 1d0))))
866 (cond ((< (abs (qd-0 a)) (sqrt most-positive-double-float))
867 (let ((a^2 (sqr-qd a)))
868 (add-qd (scale-float-qd (log1p-qd a^2) -1)
869 (log1p-qd (div-qd a
870 (sqrt-qd (add-qd-d a^2 1d0)))))))
871 #+cmu
872 ((float-infinity-p (qd-0 a))
875 (if (minusp-qd a)
876 (neg-qd (asinh-qd (neg-qd a)))
877 (let ((1/a (div-qd (make-qd-d 1d0) a)))
878 (+ (log-qd a)
879 (log1p-qd (sqrt-qd (add-qd-d (sqr-qd 1/a) 1d0)))))))))
881 (defun acosh-qd (a)
882 "Acosh(a)"
883 (declare (type %quad-double a))
884 ;; acosh(x) = log(x + sqrt(x^2-1))
885 #+nil
886 (log-qd (add-qd a
887 (sqrt-qd (sub-qd-d (sqr-qd a)
888 1d0))))
889 ;; log(x+sqrt(x^2-1)) = log(x+sqrt((x-1)*(x+1)))
890 ;; = log(x+sqrt(x-1)*sqrt(x+1))
891 #+nil
892 (log-qd (add-qd a
893 (mul-qd
894 (sqrt-qd (sub-qd-d a 1d0))
895 (sqrt-qd (add-qd-d a 1d0)))))
896 ;; Let x = 1 + y
897 ;; log(1 + y + sqrt(y)*sqrt(y + 2))
898 ;; = log1p(y + sqrt(y)*sqrt(y + 2))
900 ;; However, that doesn't work well if x is large.
902 ;; log(x+sqrt(x^2-1)) = log(x+x*sqrt(1-1/x^2))
903 ;; = log(x) + log(1+sqrt(1-1/x^2))
904 ;; = log(x) + log1p(sqrt(1-1/x)*sqrt(1+1/x))
906 (cond ((< (abs (qd-0 a)) (sqrt most-positive-double-float))
907 (let ((y (sub-qd-d a 1d0)))
908 (log1p-qd (add-qd y (sqrt-qd (mul-qd y (add-qd-d y 2d0)))))))
909 #+cmu
910 ((float-infinity-p (qd-0 a))
913 (let ((1/a (div-qd (make-qd-d 1d0) a)))
914 (+ (log-qd a)
915 (log1p-qd (mul-qd (sqrt-qd (sub-d-qd 1d0 1/a))
916 (sqrt-qd (add-d-qd 1d0 1/a)))))))))
918 (defun atanh-qd (a)
919 "Atanh(a)"
920 (declare (type %quad-double a))
921 ;; atanh(x) = 1/2*log((1+x)/(1-x))
922 ;; = 1/2*log(1+(2*x)/(1-x))
923 ;; This latter expression works better for small x
924 #+nil
925 (scale-float-qd (log-qd (div-qd (add-d-qd 1d0 a)
926 (sub-d-qd 1d0 a)))
928 ;; atanh(+/-1) = +/- infinity. Signal a division by zero or return
929 ;; infinity if the division-by-zero trap is disabled.
930 (if (qd-= (abs-qd a) +qd-one+)
931 (div-qd (make-qd-d (float-sign (qd-0 a)))
932 +qd-zero+)
933 (scale-float-qd (log1p-qd (div-qd (scale-float-qd a 1)
934 (sub-d-qd 1d0 a)))
935 -1)))
938 (defun random-qd (&optional (state *random-state*))
939 "Generate a quad-double random number in the range [0,1)"
940 (declare (optimize (speed 3)))
941 ;; Strategy: Generate 31 bits at a time, shift the bits and repeat 7 times.
942 (let* ((r +qd-zero+)
943 (m-const (scale-float 1d0 -31))
944 (m m-const))
945 (declare (type %quad-double r)
946 (double-float m-const m))
947 (dotimes (k 7)
948 (let ((d (cl:* m (random #x7fffffff state))))
949 (setf r (add-qd-d r d))
950 (setf m (cl:* m m-const))))