1 ;;;; -*- Mode: lisp -*-
3 ;;;; Copyright (c) 2007 Raymond Toy
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
14 ;;;; The above copyright notice and this permission notice shall be
15 ;;;; included in all copies or substantial portions of the Software.
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 ;;; This file contains the core routines for basic arithmetic
27 ;;; operations on a %quad-double. This includes addition,
28 ;;; subtraction, multiplication, division, negation. and absolute
29 ;;; value. Some additional helper functions are included such as
30 ;;; raising to an integer power. and the n'th root of a (non-negative)
31 ;;; %quad-double. The basic comparison operators are included, and
32 ;;; some simple tests for zerop, onep, plusp, and minusp.
34 ;;; The basic algorithms are based on Yozo Hida's double-double
35 ;;; implementation. However, some were copied from CMUCL and modified
36 ;;; to support quad-doubles.
42 (eval-when (:compile-toplevel
)
43 (setf *inline-expansion-limit
* 1600))
45 ;; All of the following functions should be inline.
46 (declaim (inline three-sum three-sum2
))
48 ;; Internal routines for implementing quad-double.
49 (defun three-sum (a b c
)
50 (declare (double-float a b c
)
52 (multiple-value-bind (t1 t2
)
54 (multiple-value-bind (a t3
)
56 (multiple-value-bind (b c
)
60 (defun three-sum2 (a b c
)
61 (declare (double-float a b c
)
63 (multiple-value-bind (t1 t2
)
65 (multiple-value-bind (a t3
)
67 (values a
(cl:+ t2 t3
) c
))))
71 (declaim (inline quick-three-accum
))
73 (defun quick-three-accum (a b c
)
74 (declare (double-float a b c
)
75 (optimize (speed 3) (space 0)))
76 (multiple-value-bind (s b
)
78 (multiple-value-bind (s a
)
83 (return-from quick-three-accum
(values (cl:+ s
0d0
) (cl:+ a
0d0
) (cl:+ b
0d0
))))
93 ;; These functions are quite short, so we inline them to minimize
95 (declaim (inline make-qd-d
116 ;; Should these functions be inline? The QD C++ source has these as
117 ;; inline functions, but these are fairly large functions. However,
118 ;; inlining makes quite a big difference in speed and consing.
120 (declaim (#+qd-inline inline
121 #-qd-inline maybe-inline
135 #-
(or qd-inline
(not cmu
))
136 (declaim (ext:start-block renorm-4 renorm-5
138 add-qd-d add-d-qd add-qd-dd
142 sub-qd sub-qd-dd sub-qd-d sub-d-qd
143 mul-qd-d mul-qd-dd mul-qd
145 div-qd div-qd-d div-qd-dd
150 (defun quick-renorm (c0 c1 c2 c3 c4
)
151 (declare (double-float c0 c1 c2 c3 c4
)
152 (optimize (speed 3)))
153 (multiple-value-bind (s t3
)
154 (quick-two-sum c3 c4
)
155 (multiple-value-bind (s t2
)
157 (multiple-value-bind (s t1
)
159 (multiple-value-bind (c0 t0
)
161 (multiple-value-bind (s t2
)
162 (quick-two-sum t2 t3
)
163 (multiple-value-bind (s t1
)
165 (multiple-value-bind (c1 t0
)
167 (multiple-value-bind (s t1
)
168 (quick-two-sum t1 t2
)
169 (multiple-value-bind (c2 t0
)
171 (values c0 c1 c2
(cl:+ t0 t1
))))))))))))
173 (defun renorm-4 (c0 c1 c2 c3
)
174 (declare (double-float c0 c1 c2 c3
)
175 (optimize (speed 3) (safety 0)))
178 (multiple-value-bind (s0 c3
)
179 (quick-two-sum c2 c3
)
180 (multiple-value-bind (s0 c2
)
181 (quick-two-sum c1 s0
)
182 (multiple-value-bind (c0 c1
)
183 (quick-two-sum c0 s0
)
187 (multiple-value-setq (s1 s2
)
188 (quick-two-sum s1 c2
))
190 (multiple-value-setq (s2 s3
)
191 (quick-two-sum s2 c3
))
192 (multiple-value-setq (s1 s2
)
193 (quick-two-sum s1 c3
))))
195 (multiple-value-setq (s0 s1
)
196 (quick-two-sum s0 c2
))
198 (multiple-value-setq (s1 s2
)
199 (quick-two-sum s1 c3
))
200 (multiple-value-setq (s0 s1
)
201 (quick-two-sum s0 c3
)))))
202 (values s0 s1 s2 s3
)))))))
204 (defun renorm-5 (c0 c1 c2 c3 c4
)
205 (declare (double-float c0 c1 c2 c3
)
206 (optimize (speed 3) (safety 0)))
209 (declare (double-float s2 s3
))
210 (multiple-value-bind (s0 c4
)
211 (quick-two-sum c3 c4
)
212 (multiple-value-bind (s0 c3
)
213 (quick-two-sum c2 s0
)
214 (multiple-value-bind (s0 c2
)
215 (quick-two-sum c1 s0
)
216 (multiple-value-bind (c0 c1
)
217 (quick-two-sum c0 s0
)
220 (declare (double-float s0 s1
))
221 (multiple-value-setq (s0 s1
)
222 (quick-two-sum c0 c1
))
224 (multiple-value-setq (s1 s2
)
225 (quick-two-sum s1 c2
))
227 (multiple-value-setq (s2 s3
)
228 (quick-two-sum s2 c3
))
233 (multiple-value-setq (s1 s2
)
234 (quick-two-sum s1 c3
))
236 (multiple-value-setq (s2 s3
)
237 (quick-two-sum s2 c4
))
238 (multiple-value-setq (s1 s2
)
239 (quick-two-sum s1 c4
))))))
241 (multiple-value-setq (s0 s1
)
242 (quick-two-sum s0 c2
))
244 (multiple-value-setq (s1 s2
)
245 (quick-two-sum s1 c3
))
247 (multiple-value-setq (s2 s3
)
248 (quick-two-sum s2 c4
))
249 (multiple-value-setq (s1 s2
)
250 (quick-two-sum s1 c4
))))
252 (multiple-value-setq (s0 s1
)
253 (quick-two-sum s0 c3
))
255 (multiple-value-setq (s1 s2
)
256 (quick-two-sum s1 c4
))
257 (multiple-value-setq (s0 s1
)
258 (quick-two-sum s0 c4
)))))))
259 (values s0 s1 s2 s3
))))))))
261 (defun make-qd-d (a0 &optional
(a1 0d0 a1-p
) (a2 0d0
) (a3 0d0
))
262 "Create a %quad-double from four double-floats, appropriately
263 normalizing the result from the four double-floats.
265 (declare (double-float a0 a1 a2 a3
)
268 (ext:inhibit-warnings
3)))
270 (multiple-value-bind (s0 s1 s2 s3
)
271 (renorm-4 a0 a1 a2 a3
)
272 (%make-qd-d s0 s1 s2 s3
))
273 (%make-qd-d a0
0d0
0d0
0d0
)))
277 ;; Quad-double + double
278 (defun add-qd-d (a b
)
279 "Add a quad-double A and a double-float B"
280 (declare (type %quad-double a
)
284 (multiple-value-bind (c0 e
)
287 (when (float-infinity-p c0
)
288 (return-from add-qd-d
(%make-qd-d c0
0d0
0d0
0d0
)))
289 (multiple-value-bind (c1 e
)
291 (multiple-value-bind (c2 e
)
293 (multiple-value-bind (c3 e
)
295 (multiple-value-bind (r0 r1 r2 r3
)
296 (renorm-5 c0 c1 c2 c3 e
)
297 (if (and (zerop (qd-0 a
)) (zerop b
))
298 (%make-qd-d c0
0d0
0d0
0d0
)
299 (%make-qd-d r0 r1 r2 r3
))))))))
301 (defun add-d-qd (a b
)
302 (declare (double-float a
)
303 (type %quad-double b
)
304 (optimize (speed 3)))
308 (defun add-qd-dd (a b
)
309 "Add a quad-double A and a double-double B"
310 (declare (type %quad-double a
)
311 (double-double-float b
)
314 (multiple-value-bind (s0 t0
)
315 (two-sum (qd-0 a
) (kernel:double-double-hi b
))
316 (multiple-value-bind (s1 t1
)
317 (two-sum (qd-1 a
) (kernel:double-double-lo b
))
318 (multiple-value-bind (s1 t0
)
320 (multiple-value-bind (s2 t0 t1
)
321 (three-sum (qd-2 a
) t0 t1
)
322 (multiple-value-bind (s3 t0
)
323 (two-sum t0
(qd-3 a
))
324 (let ((t0 (cl:+ t0 t1
)))
325 (multiple-value-call #'%make-qd-d
326 (renorm-5 s0 s1 s2 s3 t0
)))))))))
329 (defun add-dd-qd (a b
)
330 (declare (double-double-float a
)
331 (type %quad-double b
)
338 (defun add-qd-1 (a b
)
339 (declare (type %quad-double a b
)
340 (optimize (speed 3)))
341 (multiple-value-bind (s0 t0
)
342 (two-sum (qd-0 a
) (qd-0 b
))
343 (multiple-value-bind (s1 t1
)
344 (two-sum (qd-1 a
) (qd-1 b
))
345 (multiple-value-bind (s2 t2
)
346 (two-sum (qd-2 a
) (qd-2 b
))
347 (multiple-value-bind (s3 t3
)
348 (two-sum (qd-3 a
) (qd-3 b
))
349 (multiple-value-bind (s1 t0
)
351 (multiple-value-bind (s2 t0 t1
)
353 (multiple-value-bind (s3 t0
)
354 (three-sum2 s3 t0 t2
)
355 (let ((t0 (cl:+ t0 t1 t3
)))
356 (multiple-value-call #'%make-qd-d
357 (renorm-5 s0 s1 s2 s3 t0
)))))))))))
359 ;; Same as above, except that everything is expanded out for compilers
360 ;; which don't do a very good job with dataflow. CMUCL is one of
364 (declare (type %quad-double a b
)
367 ;; This is the version that is NOT IEEE. Should we use the IEEE
368 ;; version? It's quite a bit more complicated.
370 ;; In addition, this is reorganized to minimize data dependency.
371 (multiple-value-bind (a0 a1 a2 a3
)
373 (multiple-value-bind (b0 b1 b2 b3
)
375 (let ((s0 (cl:+ a0 b0
))
379 (declare (double-float s0 s1 s2 s3
))
381 (when (float-infinity-p s0
)
382 (return-from add-qd
(%make-qd-d s0
0d0
0d0
0d0
)))
383 (let ((v0 (cl:- s0 a0
))
387 (let ((u0 (cl:- s0 v0
))
391 (let ((w0 (cl:- a0 u0
))
395 (let ((u0 (cl:- b0 v0
))
399 (let ((t0 (cl:+ w0 u0
))
403 (multiple-value-bind (s1 t0
)
405 (multiple-value-bind (s2 t0 t1
)
407 (multiple-value-bind (s3 t0
)
408 (three-sum2 s3 t0 t2
)
409 (declare (double-float t0
))
410 (setf t0
(cl:+ t0 t1 t3
))
412 (multiple-value-setq (s0 s1 s2 s3
)
413 (renorm-5 s0 s1 s2 s3 t0
))
414 (if (and (zerop a0
) (zerop b0
))
415 (%make-qd-d
(+ a0 b0
) 0d0
0d0
0d0
)
416 (%make-qd-d s0 s1 s2 s3
))))))))))))))
419 (declare (type %quad-double a
))
420 (multiple-value-bind (a0 a1 a2 a3
)
422 (%make-qd-d
(cl:- a0
) (cl:- a1
) (cl:- a2
) (cl:- a3
))))
425 (declare (type %quad-double a b
))
426 (add-qd a
(neg-qd b
)))
429 (defun sub-qd-dd (a b
)
430 (declare (type %quad-double a
)
431 (type double-double-float b
))
432 (add-qd-dd a
(cl:- b
)))
434 (defun sub-qd-d (a b
)
435 (declare (type %quad-double a
)
436 (type double-float b
))
437 (add-qd-d a
(cl:- b
)))
439 (defun sub-d-qd (a b
)
440 (declare (type double-float a
)
441 (type %quad-double b
))
443 (add-d-qd a
(neg-qd b
)))
447 ;; (mul-qd-d (sqrt-qd (make-qd-dd 2w0 0w0)) 10d0) ->
448 ;; 14.1421356237309504880168872420969807856967187537694807317667973799q0
451 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
453 (defun mul-qd-d (a b
)
454 "Multiply quad-double A with B"
455 (declare (type %quad-double a
)
459 (multiple-value-bind (p0 q0
)
460 (two-prod (qd-0 a
) b
)
462 (when (float-infinity-p p0
)
463 (return-from mul-qd-d
(%make-qd-d p0
0d0
0d0
0d0
)))
464 (multiple-value-bind (p1 q1
)
465 (two-prod (qd-1 a
) b
)
466 (multiple-value-bind (p2 q2
)
467 (two-prod (qd-2 a
) b
)
468 (let ((p3 (cl:* (qd-3 a
) b
))
471 (format t
"q0 p1 = ~A ~A~%" q0 p1
)
472 (multiple-value-bind (s1 s2
)
475 (format t
"s1 s2 = ~A ~A~%" s1 s2
)
477 (format t
"s2 q1 p2 = ~A ~A ~A~%"
479 (multiple-value-bind (s2 q1 p2
)
482 (format t
"s2,q1,p2 = ~A ~A ~A~%"
485 (format t
"q1 q2 p3 = ~A ~A ~A~%"
487 (multiple-value-bind (q1 q2
)
488 (three-sum2 q1 q2 p3
)
490 (format t
"q1 q2, p3 = ~A ~A ~A~%" q1 q2 p3
)
499 (format t
"~a~%" s4
))
500 (multiple-value-bind (s0 s1 s2 s3
)
501 (renorm-5 s0 s1 s2 s3 s4
)
508 (format t
"~a~%" s4
))
510 (%make-qd-d
(float-sign p0
0d0
) 0d0
0d0
0d0
)
511 (%make-qd-d s0 s1 s2 s3
))))))))))))
523 ;; (mul-qd-dd (sqrt-qd (make-qd-dd 2w0 0w0)) 10w0) ->
524 ;; 14.142135623730950488016887242097022172449805747901877456053837224q0
527 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
528 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
530 ;; Running a test program using qd (2.1.210) shows that we get the
531 ;; same wrong answer.
533 (defun mul-qd-dd (a b
)
534 (declare (type %quad-double a
)
535 (double-double-float b
)
536 (optimize (speed 3)))
537 (multiple-value-bind (p0 q0
)
538 (two-prod (qd-0 a
) (kernel:double-double-hi b
))
539 (multiple-value-bind (p1 q1
)
540 (two-prod (qd-0 a
) (kernel:double-double-lo b
))
541 (multiple-value-bind (p2 q2
)
542 (two-prod (qd-1 a
) (kernel:double-double-hi b
))
543 (multiple-value-bind (p3 q3
)
544 (two-prod (qd-1 a
) (kernel:double-double-lo b
))
545 (multiple-value-bind (p4 q4
)
546 (two-prod (qd-2 a
) (kernel:double-double-hi b
))
547 (format t
"p0, q0 = ~A ~A~%" p0 q0
)
548 (format t
"p1, q1 = ~A ~A~%" p1 q1
)
549 (format t
"p2, q2 = ~A ~A~%" p2 q2
)
550 (format t
"p3, q3 = ~A ~A~%" p3 q3
)
551 (format t
"p4, q4 = ~A ~A~%" p4 q4
)
552 (multiple-value-setq (p1 p2 q0
)
553 (three-sum p1 p2 q0
))
554 (format t
"p1 = ~A~%" p1
)
555 (format t
"p2 = ~A~%" p2
)
556 (format t
"q0 = ~A~%" q0
)
558 (multiple-value-setq (p2 p3 p4
)
559 (three-sum p2 p3 p4
))
560 (format t
"p2 = ~A~%" p2
)
561 (format t
"p3 = ~A~%" p3
)
562 (format t
"p4 = ~A~%" p4
)
563 (multiple-value-setq (q1 q2
)
565 (multiple-value-bind (s0 t0
)
567 (multiple-value-bind (s1 t1
)
569 (multiple-value-setq (s1 t0
)
571 (let ((s2 (cl:+ t0 t1 p4
))
573 (p3 (cl:+ (cl:* (qd-2 a
)
574 (kernel:double-double-hi b
))
576 (kernel:double-double-lo b
))
578 (multiple-value-setq (p3 q0 s1
)
579 (three-sum2 p3 q0 s1
))
580 (let ((p4 (cl:+ q0 s2
)))
581 (multiple-value-call #'%make-qd-d
582 (renorm-5 p0 p1 p2 p3 p4
))))))))))))
596 ;; (mul-qd (sqrt-qd (make-qd-dd 2w0 0w0)) (make-qd-dd 10w0 0w0)) ->
597 ;; 14.1421356237309504880168872420969807856967187537694807317667973799q0
600 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
602 (declare (type %quad-double a b
)
605 (multiple-value-bind (a0 a1 a2 a3
)
607 (multiple-value-bind (b0 b1 b2 b3
)
609 (multiple-value-bind (p0 q0
)
612 (when (float-infinity-p p0
)
613 (return-from mul-qd
(%make-qd-d p0
0d0
0d0
0d0
)))
614 (multiple-value-bind (p1 q1
)
616 (multiple-value-bind (p2 q2
)
618 (multiple-value-bind (p3 q3
)
620 (multiple-value-bind (p4 q4
)
622 (multiple-value-bind (p5 q5
)
624 ;; Start accumulation
625 (multiple-value-setq (p1 p2 q0
)
626 (three-sum p1 p2 q0
))
628 ;; six-three-sum of p2, q1, q2, p3, p4, p5
629 (multiple-value-setq (p2 q1 q2
)
630 (three-sum p2 q1 q2
))
631 (multiple-value-setq (p3 p4 p5
)
632 (three-sum p3 p4 p5
))
633 ;; Compute (s0,s1,s2) = (p2,q1,q2) + (p3,p4,p5)
634 (multiple-value-bind (s0 t0
)
636 (multiple-value-bind (s1 t1
)
638 (let ((s2 (cl:+ q2 p5
)))
639 (declare (double-float s2
))
640 (multiple-value-bind (s1 t0
)
642 (declare (double-float s1
))
643 (incf s2
(cl:+ t0 t1
))
644 ;; O(eps^3) order terms. This is the sloppy
645 ;; multiplication version. Should we use
646 ;; the precise version? It's significantly
649 (incf s1
(cl:+ (cl:* a0 b3
)
655 (format t
"p0,p1,s0,s1,s2 = ~a ~a ~a ~a ~a~%"
657 (multiple-value-bind (r0 r1 s0 s1
)
658 (renorm-5 p0 p1 s0 s1 s2
)
660 (%make-qd-d p0
0d0
0d0
0d0
)
661 (%make-qd-d r0 r1 s0 s1
))))))))))))))))
663 ;; This is the non-sloppy version. I think this works just fine, but
664 ;; since qd defaults to the sloppy multiplication version, we do the
668 (declare (type %quad-double a b
)
669 (optimize (speed 3)))
670 (multiple-value-bind (a0 a1 a2 a3
)
672 (multiple-value-bind (b0 b1 b2 b3
)
674 (multiple-value-bind (p0 q0
)
676 (multiple-value-bind (p1 q1
)
678 (multiple-value-bind (p2 q2
)
680 (multiple-value-bind (p3 q3
)
682 (multiple-value-bind (p4 q4
)
684 (declare (double-float q4
))
687 (format t
"p0, q0 = ~a ~a~%" p0 q0
)
688 (format t
"p1, q1 = ~a ~a~%" p1 q1
)
689 (format t
"p2, q2 = ~a ~a~%" p2 q2
)
690 (format t
"p3, q3 = ~a ~a~%" p3 q3
)
691 (format t
"p4, q4 = ~a ~a~%" p4 q4
))
692 (multiple-value-bind (p5 q5
)
695 (format t
"p5, q5 = ~a ~a~%" p5 q5
)
696 ;; Start accumulation
697 (multiple-value-setq (p1 p2 q0
)
698 (three-sum p1 p2 q0
))
700 (format t
"p1 p2 q0 = ~a ~a ~a~%" p1 p2 q0
)
701 ;; six-three-sum of p2, q1, q2, p3, p4, p5
702 (multiple-value-setq (p2 q1 q2
)
703 (three-sum p2 q1 q2
))
704 (multiple-value-setq (p3 p4 p5
)
705 (three-sum p3 p4 p5
))
706 ;; Compute (s0,s1,s2) = (p2,q1,q2) + (p3,p4,p5)
707 (multiple-value-bind (s0 t0
)
709 (multiple-value-bind (s1 t1
)
711 (declare (double-float t1
))
712 (let ((s2 (cl:+ q2 p5
)))
713 (declare (double-float s2
))
714 (multiple-value-bind (s1 t0
)
716 (declare (double-float s1
))
717 (incf s2
(cl:+ t0 t1
))
718 (multiple-value-bind (p6 q6
)
720 (multiple-value-bind (p7 q7
)
722 (multiple-value-bind (p8 q8
)
724 (multiple-value-bind (p9 q9
)
726 (multiple-value-setq (q0 q3
)
728 (multiple-value-setq (q4 q5
)
730 (multiple-value-setq (p6 p7
)
732 (multiple-value-setq (p8 p9
)
734 ;; (t0,t1) = (q0,q3)+(q4,q5)
735 (multiple-value-setq (t0 t1
)
737 (setf t1
(cl:+ q3 q5
))
738 ;; (r0,r1) = (p6,p7)+(p8,p9)
739 (multiple-value-bind (r0 r1
)
741 (declare (double-float r1
))
742 (incf r1
(cl:+ p7 p9
))
743 ;; (q3,q4) = (t0,t1)+(r0,r1)
744 (multiple-value-setq (q3 q4
)
746 (incf q4
(cl:+ t1 r1
))
747 ;; (t0,t1)=(q3,q4)+s1
748 (multiple-value-setq (t0 t1
)
759 (format t
"p0,p1,s0,t0,t1 = ~a ~a ~a ~a ~a~%"
761 (multiple-value-call #'%make-qd-d
762 (renorm-5 p0 p1 s0 t0 t1
))))))))))))))))))))
766 (declare (type %quad-double a
)
769 (multiple-value-bind (p0 q0
)
771 (multiple-value-bind (p1 q1
)
772 (two-prod (cl:* 2 (qd-0 a
)) (qd-1 a
))
773 (multiple-value-bind (p2 q2
)
774 (two-prod (cl:* 2 (qd-0 a
)) (qd-2 a
))
775 (multiple-value-bind (p3 q3
)
777 (multiple-value-setq (p1 q0
)
779 (multiple-value-setq (q0 q1
)
781 (multiple-value-setq (p2 p3
)
784 (multiple-value-bind (s0 t0
)
786 (declare (double-float t0
))
787 (multiple-value-bind (s1 t1
)
789 (declare (double-float t1
))
790 (multiple-value-setq (s1 t0
)
794 (multiple-value-setq (s1 t0
)
795 (quick-two-sum s1 t0
))
796 (multiple-value-setq (p2 t1
)
797 (quick-two-sum s0 s1
))
798 (multiple-value-setq (p3 q0
)
799 (quick-two-sum t1 t0
))
801 (let ((p4 (cl:* 2 (qd-0 a
) (qd-3 a
)))
802 (p5 (cl:* 2 (qd-1 a
) (qd-2 a
))))
803 (declare (double-float p4
))
804 (multiple-value-setq (p4 p5
)
806 (multiple-value-setq (q2 q3
)
809 (multiple-value-setq (t0 t1
)
812 (incf t1
(cl:+ p5 q3
))
814 (multiple-value-setq (p3 p4
)
816 (incf p4
(cl:+ q0 t1
))
818 (multiple-value-call #'%make-qd-d
819 (renorm-5 p0 p1 p2 p3 p4
))))))))))
824 (declare (type %quad-double a b
)
829 (let* ((q0 (cl:/ a0 b0
))
830 (r (sub-qd a
(mul-qd-d b q0
)))
831 (q1 (cl:/ (qd-0 r
) b0
)))
833 (when (float-infinity-p q0
)
834 (return-from div-qd
(%make-qd-d q0
0d0
0d0
0d0
)))
835 (setf r
(sub-qd r
(mul-qd-d b q1
)))
836 (let ((q2 (cl:/ (qd-0 r
) b0
)))
837 (setf r
(sub-qd r
(mul-qd-d b q2
)))
838 (let ((q3 (cl:/ (qd-0 r
) b0
)))
839 (multiple-value-bind (q0 q1 q2 q3
)
840 (renorm-4 q0 q1 q2 q3
)
841 (%make-qd-d q0 q1 q2 q3
)))))))
844 (declare (type %quad-double a b
)
849 (let* ((q0 (cl:/ a0 b0
))
850 (r (sub-qd a
(mul-qd-d b q0
)))
851 (q1 (cl:/ (qd-0 r
) b0
)))
852 (when (float-infinity-p q0
)
853 (return-from div-qd
(%make-qd-d q0
0d0
0d0
0d0
)))
854 (setf r
(sub-qd r
(mul-qd-d b q1
)))
855 (let ((q2 (cl:/ (qd-0 r
) b0
)))
856 (setf r
(sub-qd r
(mul-qd-d b q2
)))
857 (let ((q3 (cl:/ (qd-0 r
) b0
)))
858 (multiple-value-bind (q0 q1 q2 q3
)
859 (renorm-4 q0 q1 q2 q3
)
860 (%make-qd-d q0 q1 q2 q3
)))))))
865 (declare (type %quad-double a b
))
868 (let* ((q0 (cl:/ a0 b0
))
869 (r (sub-qd a
(mul-qd-d b q0
)))
870 (q1 (cl:/ (qd-0 r
) b0
)))
871 (setf r
(sub-qd r
(mul-qd-d b q1
)))
872 (let ((q2 (cl:/ (qd-0 r
) b0
)))
873 (setf r
(sub-qd r
(mul-qd-d b q2
)))
874 (let ((q3 (cl:/ (qd-0 r
) b0
)))
875 (setf r
(sub-qd r
(mul-qd-d b q3
)))
876 (let ((q4 (cl:/ (qd-0 r
) b0
)))
877 (multiple-value-bind (q0 q1 q2 q3
)
878 (renorm-5 q0 q1 q2 q3 q4
)
879 (%make-qd-d q0 q1 q2 q3
))))))))
881 ;; quad-double / double
882 (defun div-qd-d (a b
)
883 (declare (type %quad-double a
)
887 ;; Compute approximate quotient using high order doubles, then
888 ;; correct it 3 times using the remainder. Analogous to long
890 (let ((q0 (cl:/ (qd-0 a
) b
)))
892 (when (float-infinity-p q0
)
893 (return-from div-qd-d
(%make-qd-d q0
0d0
0d0
0d0
)))
895 ;; Compute remainder a - q0 * b
896 (multiple-value-bind (t0 t1
)
898 (let ((r #+cmu
(sub-qd-dd a
(kernel:make-double-double-float t0 t1
))
899 #-cmu
(sub-qd a
(make-qd-d t0 t1
0d0
0d0
))))
901 (let ((q1 (cl:/ (qd-0 r
) b
)))
902 (multiple-value-bind (t0 t1
)
904 (setf r
#+cmu
(sub-qd-dd r
(kernel:make-double-double-float t0 t1
))
905 #-cmu
(sub-qd r
(make-qd-d t0 t1
0d0
0d0
)))
907 (let ((q2 (cl:/ (qd-0 r
) b
)))
908 (multiple-value-bind (t0 t1
)
910 (setf r
#+cmu
(sub-qd-dd r
(kernel:make-double-double-float t0 t1
))
911 #-cmu
(sub-qd r
(make-qd-d t0 t1
0d0
0d0
)))
913 (let ((q3 (cl:/ (qd-0 r
) b
)))
914 (make-qd-d q0 q1 q2 q3
))))))))))
918 (defun div-qd-dd (a b
)
919 (declare (type %quad-double a
)
920 (double-double-float b
)
923 (let* ((q0 (cl:/ (qd-0 a
) (kernel:double-double-hi b
)))
924 (r (sub-qd-dd a
(cl:* b q0
))))
925 (when (float-infinity-p q0
)
926 (return-from div-qd-dd
(%make-qd-d q0
0d0
0d0
0d0
)))
927 (let ((q1 (cl:/ (qd-0 r
) (kernel:double-double-hi b
))))
928 (setf r
(sub-qd-dd r
(cl:* b q1
)))
929 (let ((q2 (cl:/ (qd-0 r
) (kernel:double-double-hi b
))))
930 (setf r
(sub-qd-dd r
(cl:* b q2
)))
931 (let ((q3 (cl:/ (qd-0 r
) (kernel:double-double-hi b
))))
932 (make-qd-d q0 q1 q2 q3
))))))
935 (defun make-qd-dd (a0 a1
)
936 "Create a %quad-double from two double-double-floats"
937 (declare (double-double-float a0 a1
)
938 (optimize (speed 3) (space 0)))
939 (make-qd-d (kernel:double-double-hi a0
)
940 (kernel:double-double-lo a0
)
941 (kernel:double-double-hi a1
)
942 (kernel:double-double-lo a1
)))
945 #-
(or qd-inline
(not cmu
))
946 (declaim (ext:end-block
))
949 (declare (type %quad-double a
))
950 (if (minusp (float-sign (qd-0 a
)))
954 ;; a^n for an integer n
956 (declare (type %quad-double a
)
961 (return-from npow
(make-qd-d 1d0
)))
966 (declare (type (and fixnum unsigned-byte
) abs-n
)
967 (type %quad-double r s
))
969 ;; Binary exponentiation
970 (loop while
(plusp abs-n
)
972 (when (= 1 (logand abs-n
1))
973 (setf s
(mul-qd s r
)))
974 (setf abs-n
(ash abs-n -
1))
976 (setf r
(sqr-qd r
)))))
980 (div-qd (make-qd-d 1d0
) s
)
983 ;; The n'th root of a. n is an positive integer and a should be
985 (defun nroot-qd (a n
)
986 (declare (type %quad-double a
)
987 (type (and fixnum unsigned-byte
) n
)
990 ;; Use Newton's iteration to solve
994 ;; The iteration becomes
996 ;; x' = x + x * (1 - a * x^n)/n
998 ;; Since Newton's iteration converges quadratically, we only need to
1000 (let ((r (make-qd-d (expt (the (double-float (0d0)) (qd-0 a
))
1001 (cl:-
(cl:/ (float n
1d0
)))))))
1002 (declare (type %quad-double r
))
1005 (add-qd-d (neg-qd (mul-qd a
(npow r n
)))
1009 (setf r
(add-qd r
(term))))
1010 (div-qd (make-qd-d 1d0
) r
))))
1014 (or (< (qd-0 a
) (qd-0 b
))
1015 (and (= (qd-0 a
) (qd-0 b
))
1016 (or (< (qd-1 a
) (qd-1 b
))
1017 (and (= (qd-1 a
) (qd-1 b
))
1018 (or (< (qd-2 a
) (qd-2 b
))
1019 (and (= (qd-2 a
) (qd-2 b
))
1020 (< (qd-3 a
) (qd-3 b
)))))))))
1024 (or (> (qd-0 a
) (qd-0 b
))
1025 (and (= (qd-0 a
) (qd-0 b
))
1026 (or (> (qd-1 a
) (qd-1 b
))
1027 (and (= (qd-1 a
) (qd-1 b
))
1028 (or (> (qd-2 a
) (qd-2 b
))
1029 (and (= (qd-2 a
) (qd-2 b
))
1030 (> (qd-3 a
) (qd-3 b
)))))))))
1042 (declare (type %quad-double a
))
1047 (declare (type %quad-double a
))
1048 (and (= (qd-0 a
) 1d0
)
1055 (declare (type %quad-double a
))
1058 (defun minusp-qd (a)
1060 (declare (type %quad-double a
))
1064 (and (= (qd-0 a
) (qd-0 b
))
1065 (= (qd-1 a
) (qd-1 b
))
1066 (= (qd-2 a
) (qd-2 b
))
1067 (= (qd-3 a
) (qd-3 b
))))
1071 (defun integer-decode-qd (q)
1072 (declare (type %quad-double q
))
1073 (multiple-value-bind (hi-int hi-exp sign
)
1074 (integer-decode-float (realpart q
))
1075 (if (zerop (imagpart q
))
1076 (values (ash hi-int
106) (cl:- hi-exp
106) sign
)
1077 (multiple-value-bind (lo-int lo-exp lo-sign
)
1078 (integer-decode-float (imagpart q
))
1079 (values (cl:+ (cl:* (cl:* sign lo-sign
) lo-int
)
1080 (ash hi-int
(cl:- hi-exp lo-exp
)))
1084 (defun integer-decode-qd (q)
1085 (declare (type %quad-double q
))
1086 ;; Integer decode each component and then create the appropriate
1087 ;; integer by shifting and add all the parts together.
1088 (multiple-value-bind (q0-int q0-exp q0-sign
)
1089 (integer-decode-float (qd-0 q
))
1090 (multiple-value-bind (q1-int q1-exp q1-sign
)
1091 (integer-decode-float (qd-1 q
))
1092 ;; Note: Some systems return an exponent of 0 if the number is
1093 ;; zero. If so, everything is easier if we pretend the exponent
1095 (when (zerop (qd-1 q
))
1096 (setf q1-exp -
1075))
1097 (multiple-value-bind (q2-int q2-exp q2-sign
)
1098 (integer-decode-float (qd-2 q
))
1099 (when (zerop (qd-2 q
))
1100 (setf q2-exp -
1075))
1101 (multiple-value-bind (q3-int q3-exp q3-sign
)
1102 (integer-decode-float (qd-3 q
))
1103 (when (zerop (qd-3 q
))
1104 (setf q3-exp -
1075))
1105 ;; Combine all the parts together.
1106 (values (+ (* q0-sign q3-sign q3-int
)
1107 (ash (* q0-sign q2-sign q2-int
) (- q2-exp q3-exp
))
1108 (ash (* q0-sign q1-sign q1-int
) (- q1-exp q3-exp
))
1109 (ash q0-int
(- q0-exp q3-exp
)))
1113 (declaim (inline scale-float-qd
))
1114 (defun scale-float-qd (qd k
)
1115 (declare (type %quad-double qd
)
1117 (optimize (speed 3) (space 0)))
1118 ;; (space 0) to get scale-double-float inlined
1119 (multiple-value-bind (a0 a1 a2 a3
)
1121 (make-qd-d (scale-float a0 k
)
1124 (scale-float a3 k
))))
1126 ;; The following method, which is faster doesn't work if QD is very
1127 ;; large and k is very negative because we get zero as the answer,
1128 ;; when it shouldn't be.
1130 (defun scale-float-qd (qd k
)
1131 (declare (type %quad-double qd
)
1132 ;;(type (integer -1022 1022) k)
1133 (optimize (speed 3) (space 0)))
1134 ;; (space 0) to get scale-double-float inlined
1135 (let ((scale (scale-float 1d0 k
)))
1136 (%make-qd-d
(cl:* (qd-0 qd
) scale
)
1137 (cl:* (qd-1 qd
) scale
)
1138 (cl:* (qd-2 qd
) scale
)
1139 (cl:* (qd-3 qd
) scale
))))
1141 (defun decode-float-qd (q)
1142 (declare (type %quad-double q
))
1143 (multiple-value-bind (frac exp sign
)
1144 (decode-float (qd-0 q
))
1145 (declare (ignore frac
))
1146 ;; Got the exponent. Scale the quad-double appropriately.
1147 (values (scale-float-qd q
(- exp
))