added oct package for long-long arith
[CommonLispStat.git] / external / oct / qd.lisp
blob15a67a913574cad866dc7ae1080d67ebc18d319a
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 ;;; 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.
33 ;;;
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.
39 (in-package #:qdi)
41 #+cmu
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)
51 (optimize (speed 3)))
52 (multiple-value-bind (t1 t2)
53 (two-sum a b)
54 (multiple-value-bind (a t3)
55 (two-sum c t1)
56 (multiple-value-bind (b c)
57 (two-sum t2 t3)
58 (values a b c)))))
60 (defun three-sum2 (a b c)
61 (declare (double-float a b c)
62 (optimize (speed 3)))
63 (multiple-value-bind (t1 t2)
64 (two-sum a b)
65 (multiple-value-bind (a t3)
66 (two-sum c t1)
67 (values a (cl:+ t2 t3) c))))
69 ;; Not needed????
70 #+nil
71 (declaim (inline quick-three-accum))
72 #+nil
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)
77 (two-sum b c)
78 (multiple-value-bind (s a)
79 (two-sum a s)
80 (let ((za (/= a 0))
81 (zb (/= b 0)))
82 (when (and za zb)
83 (return-from quick-three-accum (values (cl:+ s 0d0) (cl:+ a 0d0) (cl:+ b 0d0))))
84 (when (not za)
85 (setf a s)
86 (setf s 0d0))
87 (when (not zb)
88 (setf b a)
89 (setf a s))
90 (values 0d0 a b)))))
93 ;; These functions are quite short, so we inline them to minimize
94 ;; consing.
95 (declaim (inline make-qd-d
96 add-d-qd
97 add-dd-qd
98 neg-qd
99 sub-qd
100 sub-qd-dd
101 sub-qd-d
102 sub-d-qd
103 make-qd-dd
104 abs-qd
105 qd->
106 qd-<
107 qd->=
108 qd-<=
109 zerop-qd
110 onep-qd
111 plusp-qd
112 minusp-qd
113 qd-=
114 scale-float-qd))
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.
119 #+cmu
120 (declaim (#+qd-inline inline
121 #-qd-inline maybe-inline
122 renorm-4
123 renorm-5
124 add-qd-d
125 add-qd-dd
126 add-qd
127 mul-qd-d
128 mul-qd-dd
129 mul-qd
130 sqr-qd
131 div-qd
132 div-qd-d
133 div-qd-dd))
135 #-(or qd-inline (not cmu))
136 (declaim (ext:start-block renorm-4 renorm-5
137 make-qd-d
138 add-qd-d add-d-qd add-qd-dd
139 add-dd-qd
140 add-qd
141 neg-qd
142 sub-qd sub-qd-dd sub-qd-d sub-d-qd
143 mul-qd-d mul-qd-dd mul-qd
144 sqr-qd
145 div-qd div-qd-d div-qd-dd
146 make-qd-dd
149 #+(or)
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)
156 (quick-two-sum c2 s)
157 (multiple-value-bind (s t1)
158 (quick-two-sum c1 s)
159 (multiple-value-bind (c0 t0)
160 (quick-two-sum c0 s)
161 (multiple-value-bind (s t2)
162 (quick-two-sum t2 t3)
163 (multiple-value-bind (s t1)
164 (quick-two-sum t1 s)
165 (multiple-value-bind (c1 t0)
166 (quick-two-sum t0 s)
167 (multiple-value-bind (s t1)
168 (quick-two-sum t1 t2)
169 (multiple-value-bind (c2 t0)
170 (quick-two-sum t0 s)
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)))
176 (let ((s2 0d0)
177 (s3 0d0))
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)
184 (let ((s0 c0)
185 (s1 c1))
186 (cond ((/= s1 0)
187 (multiple-value-setq (s1 s2)
188 (quick-two-sum s1 c2))
189 (if (/= s2 0)
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))
197 (if (/= s1 0)
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)))
207 (let ((s2 0d0)
208 (s3 0d0))
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)
218 (let ((s0 c0)
219 (s1 c1))
220 (declare (double-float s0 s1))
221 (multiple-value-setq (s0 s1)
222 (quick-two-sum c0 c1))
223 (cond ((/= s1 0)
224 (multiple-value-setq (s1 s2)
225 (quick-two-sum s1 c2))
226 (cond ((/= s2 0)
227 (multiple-value-setq (s2 s3)
228 (quick-two-sum s2 c3))
229 (if (/= s3 0)
230 (incf s3 c4)
231 (incf s2 c4)))
233 (multiple-value-setq (s1 s2)
234 (quick-two-sum s1 c3))
235 (if (/= s2 0)
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))
243 (cond ((/= s1 0)
244 (multiple-value-setq (s1 s2)
245 (quick-two-sum s1 c3))
246 (if (/= s2 0)
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))
254 (if (/= s1 0)
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)
266 (optimize (speed 3)
267 #+cmu
268 (ext:inhibit-warnings 3)))
269 (if a1-p
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)))
275 ;;;; Addition
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)
281 (double-float b)
282 (optimize (speed 3)
283 (space 0)))
284 (multiple-value-bind (c0 e)
285 (two-sum (qd-0 a) b)
286 #+cmu
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)
290 (two-sum (qd-1 a) e)
291 (multiple-value-bind (c2 e)
292 (two-sum (qd-2 a) e)
293 (multiple-value-bind (c3 e)
294 (two-sum (qd-3 a) 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)))
305 (add-qd-d b a))
307 #+cmu
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)
312 (optimize (speed 3)
313 (space 0)))
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)
319 (two-sum 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)))))))))
328 #+cmu
329 (defun add-dd-qd (a b)
330 (declare (double-double-float a)
331 (type %quad-double b)
332 (optimize (speed 3)
333 (space 0)))
334 (add-qd-dd b a))
337 #+(or)
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)
350 (two-sum s1 t0)
351 (multiple-value-bind (s2 t0 t1)
352 (three-sum 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
361 ;; those compilers.
363 (defun add-qd (a b)
364 (declare (type %quad-double a b)
365 (optimize (speed 3)
366 (space 0)))
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)
372 (qd-parts a)
373 (multiple-value-bind (b0 b1 b2 b3)
374 (qd-parts b)
375 (let ((s0 (cl:+ a0 b0))
376 (s1 (cl:+ a1 b1))
377 (s2 (cl:+ a2 b2))
378 (s3 (cl:+ a3 b3)))
379 (declare (double-float s0 s1 s2 s3))
380 #+cmu
381 (when (float-infinity-p s0)
382 (return-from add-qd (%make-qd-d s0 0d0 0d0 0d0)))
383 (let ((v0 (cl:- s0 a0))
384 (v1 (cl:- s1 a1))
385 (v2 (cl:- s2 a2))
386 (v3 (cl:- s3 a3)))
387 (let ((u0 (cl:- s0 v0))
388 (u1 (cl:- s1 v1))
389 (u2 (cl:- s2 v2))
390 (u3 (cl:- s3 v3)))
391 (let ((w0 (cl:- a0 u0))
392 (w1 (cl:- a1 u1))
393 (w2 (cl:- a2 u2))
394 (w3 (cl:- a3 u3)))
395 (let ((u0 (cl:- b0 v0))
396 (u1 (cl:- b1 v1))
397 (u2 (cl:- b2 v2))
398 (u3 (cl:- b3 v3)))
399 (let ((t0 (cl:+ w0 u0))
400 (t1 (cl:+ w1 u1))
401 (t2 (cl:+ w2 u2))
402 (t3 (cl:+ w3 u3)))
403 (multiple-value-bind (s1 t0)
404 (two-sum s1 t0)
405 (multiple-value-bind (s2 t0 t1)
406 (three-sum 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))
411 ;; Renormalize
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))))))))))))))
418 (defun neg-qd (a)
419 (declare (type %quad-double a))
420 (multiple-value-bind (a0 a1 a2 a3)
421 (qd-parts a)
422 (%make-qd-d (cl:- a0) (cl:- a1) (cl:- a2) (cl:- a3))))
424 (defun sub-qd (a b)
425 (declare (type %quad-double a b))
426 (add-qd a (neg-qd b)))
428 #+cmu
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))
442 ;; a - b = a + (-b)
443 (add-d-qd a (neg-qd b)))
446 ;; Works
447 ;; (mul-qd-d (sqrt-qd (make-qd-dd 2w0 0w0)) 10d0) ->
448 ;; 14.1421356237309504880168872420969807856967187537694807317667973799q0
450 ;; Clisp says
451 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
453 (defun mul-qd-d (a b)
454 "Multiply quad-double A with B"
455 (declare (type %quad-double a)
456 (double-float b)
457 (optimize (speed 3)
458 (space 0)))
459 (multiple-value-bind (p0 q0)
460 (two-prod (qd-0 a) b)
461 #+cmu
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))
469 (s0 p0))
470 #+nil
471 (format t "q0 p1 = ~A ~A~%" q0 p1)
472 (multiple-value-bind (s1 s2)
473 (two-sum q0 p1)
474 #+nil
475 (format t "s1 s2 = ~A ~A~%" s1 s2)
476 #+nil
477 (format t "s2 q1 p2 = ~A ~A ~A~%"
478 s2 q1 p2)
479 (multiple-value-bind (s2 q1 p2)
480 (three-sum s2 q1 p2)
481 #+nil
482 (format t "s2,q1,p2 = ~A ~A ~A~%"
483 s2 q1 p2)
484 #+nil
485 (format t "q1 q2 p3 = ~A ~A ~A~%"
486 q1 q2 p3)
487 (multiple-value-bind (q1 q2)
488 (three-sum2 q1 q2 p3)
489 #+nil
490 (format t "q1 q2, p3 = ~A ~A ~A~%" q1 q2 p3)
491 (let ((s3 q1)
492 (s4 (cl:+ q2 p2)))
493 #+nil
494 (progn
495 (format t "~a~%" s0)
496 (format t "~a~%" s1)
497 (format t "~a~%" s2)
498 (format t "~a~%" s3)
499 (format t "~a~%" s4))
500 (multiple-value-bind (s0 s1 s2 s3)
501 (renorm-5 s0 s1 s2 s3 s4)
502 #+nil
503 (progn
504 (format t "~a~%" s0)
505 (format t "~a~%" s1)
506 (format t "~a~%" s2)
507 (format t "~a~%" s3)
508 (format t "~a~%" s4))
509 (if (zerop s0)
510 (%make-qd-d (float-sign p0 0d0) 0d0 0d0 0d0)
511 (%make-qd-d s0 s1 s2 s3))))))))))))
513 ;; a0 * b0 0
514 ;; a0 * b1 1
515 ;; a1 * b0 2
516 ;; a1 * b1 3
517 ;; a2 * b0 4
518 ;; a2 * b1 5
519 ;; a3 * b0 6
520 ;; a3 * b1 7
522 ;; Not working.
523 ;; (mul-qd-dd (sqrt-qd (make-qd-dd 2w0 0w0)) 10w0) ->
524 ;; 14.142135623730950488016887242097022172449805747901877456053837224q0
526 ;; But clisp says
527 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
528 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
530 ;; Running a test program using qd (2.1.210) shows that we get the
531 ;; same wrong answer.
532 #+(or)
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)
557 ;; five-three-sum
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)
564 (two-sum q1 q2))
565 (multiple-value-bind (s0 t0)
566 (two-sum p2 q1)
567 (multiple-value-bind (s1 t1)
568 (two-sum p3 q2)
569 (multiple-value-setq (s1 t0)
570 (two-sum s1 t0))
571 (let ((s2 (cl:+ t0 t1 p4))
572 (p2 s0)
573 (p3 (cl:+ (cl:* (qd-2 a)
574 (kernel:double-double-hi b))
575 (cl:* (qd-3 a)
576 (kernel:double-double-lo b))
577 q3 q4)))
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))))))))))))
584 ;; a0 * b0 0
585 ;; a0 * b1 1
586 ;; a1 * b0 2
587 ;; a0 * b2 3
588 ;; a1 * b1 4
589 ;; a2 * b0 5
590 ;; a0 * b3 6
591 ;; a1 * b2 7
592 ;; a2 * b1 8
593 ;; a3 * b0 9
595 ;; Works
596 ;; (mul-qd (sqrt-qd (make-qd-dd 2w0 0w0)) (make-qd-dd 10w0 0w0)) ->
597 ;; 14.1421356237309504880168872420969807856967187537694807317667973799q0
599 ;; Clisp says
600 ;; 14.142135623730950488016887242096980785696718753769480731766797379908L0
601 (defun mul-qd (a b)
602 (declare (type %quad-double a b)
603 (optimize (speed 3)
604 (space 0)))
605 (multiple-value-bind (a0 a1 a2 a3)
606 (qd-parts a)
607 (multiple-value-bind (b0 b1 b2 b3)
608 (qd-parts b)
609 (multiple-value-bind (p0 q0)
610 (two-prod a0 b0)
611 #+cmu
612 (when (float-infinity-p p0)
613 (return-from mul-qd (%make-qd-d p0 0d0 0d0 0d0)))
614 (multiple-value-bind (p1 q1)
615 (two-prod a0 b1)
616 (multiple-value-bind (p2 q2)
617 (two-prod a1 b0)
618 (multiple-value-bind (p3 q3)
619 (two-prod a0 b2)
620 (multiple-value-bind (p4 q4)
621 (two-prod a1 b1)
622 (multiple-value-bind (p5 q5)
623 (two-prod a2 b0)
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)
635 (two-sum p2 p3)
636 (multiple-value-bind (s1 t1)
637 (two-sum q1 p4)
638 (let ((s2 (cl:+ q2 p5)))
639 (declare (double-float s2))
640 (multiple-value-bind (s1 t0)
641 (two-sum 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
647 ;; more complex.
649 (incf s1 (cl:+ (cl:* a0 b3)
650 (cl:* a1 b2)
651 (cl:* a2 b1)
652 (cl:* a3 b0)
653 q0 q3 q4 q5))
654 #+nil
655 (format t "p0,p1,s0,s1,s2 = ~a ~a ~a ~a ~a~%"
656 p0 p1 s0 s1 s2)
657 (multiple-value-bind (r0 r1 s0 s1)
658 (renorm-5 p0 p1 s0 s1 s2)
659 (if (zerop r0)
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
665 ;; same.
666 #+nil
667 (defun mul-qd (a b)
668 (declare (type %quad-double a b)
669 (optimize (speed 3)))
670 (multiple-value-bind (a0 a1 a2 a3)
671 (qd-parts a)
672 (multiple-value-bind (b0 b1 b2 b3)
673 (qd-parts b)
674 (multiple-value-bind (p0 q0)
675 (two-prod a0 b0)
676 (multiple-value-bind (p1 q1)
677 (two-prod a0 b1)
678 (multiple-value-bind (p2 q2)
679 (two-prod a1 b0)
680 (multiple-value-bind (p3 q3)
681 (two-prod a0 b2)
682 (multiple-value-bind (p4 q4)
683 (two-prod a1 b1)
684 (declare (double-float q4))
685 #+nil
686 (progn
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)
693 (two-prod a2 b0)
694 #+nil
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))
699 #+nil
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)
708 (two-sum p2 p3)
709 (multiple-value-bind (s1 t1)
710 (two-sum q1 p4)
711 (declare (double-float t1))
712 (let ((s2 (cl:+ q2 p5)))
713 (declare (double-float s2))
714 (multiple-value-bind (s1 t0)
715 (two-sum s1 t0)
716 (declare (double-float s1))
717 (incf s2 (cl:+ t0 t1))
718 (multiple-value-bind (p6 q6)
719 (two-prod a0 b3)
720 (multiple-value-bind (p7 q7)
721 (two-prod a1 b2)
722 (multiple-value-bind (p8 q8)
723 (two-prod a2 b1)
724 (multiple-value-bind (p9 q9)
725 (two-prod a3 b0)
726 (multiple-value-setq (q0 q3)
727 (two-sum q0 q3))
728 (multiple-value-setq (q4 q5)
729 (two-sum q4 q5))
730 (multiple-value-setq (p6 p7)
731 (two-sum p6 p7))
732 (multiple-value-setq (p8 p9)
733 (two-sum p8 p9))
734 ;; (t0,t1) = (q0,q3)+(q4,q5)
735 (multiple-value-setq (t0 t1)
736 (two-sum q0 q4))
737 (setf t1 (cl:+ q3 q5))
738 ;; (r0,r1) = (p6,p7)+(p8,p9)
739 (multiple-value-bind (r0 r1)
740 (two-sum p6 p8)
741 (declare (double-float r1))
742 (incf r1 (cl:+ p7 p9))
743 ;; (q3,q4) = (t0,t1)+(r0,r1)
744 (multiple-value-setq (q3 q4)
745 (two-sum t0 r0))
746 (incf q4 (cl:+ t1 r1))
747 ;; (t0,t1)=(q3,q4)+s1
748 (multiple-value-setq (t0 t1)
749 (two-sum q3 s1))
750 (incf t1 q4)
751 ;; O(eps^4) terms
752 (incf t1
753 (cl:+ (cl:* a1 b3)
754 (cl:* a2 b2)
755 (cl:* a3 b1)
756 q6 q7 q8 q9
757 s2))
758 #+nil
759 (format t "p0,p1,s0,t0,t1 = ~a ~a ~a ~a ~a~%"
760 p0 p1 s0 t0 t1)
761 (multiple-value-call #'%make-qd-d
762 (renorm-5 p0 p1 s0 t0 t1))))))))))))))))))))
764 (defun sqr-qd (a)
765 "Square A"
766 (declare (type %quad-double a)
767 (optimize (speed 3)
768 (space 0)))
769 (multiple-value-bind (p0 q0)
770 (two-sqr (qd-0 a))
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)
776 (two-sqr (qd-1 a))
777 (multiple-value-setq (p1 q0)
778 (two-sum q0 p1))
779 (multiple-value-setq (q0 q1)
780 (two-sum q0 q1))
781 (multiple-value-setq (p2 p3)
782 (two-sum p2 p3))
784 (multiple-value-bind (s0 t0)
785 (two-sum q0 p2)
786 (declare (double-float t0))
787 (multiple-value-bind (s1 t1)
788 (two-sum q1 p3)
789 (declare (double-float t1))
790 (multiple-value-setq (s1 t0)
791 (two-sum s1 t0))
792 (incf t0 t1)
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)
805 (two-sum p4 p5))
806 (multiple-value-setq (q2 q3)
807 (two-sum q2 q3))
809 (multiple-value-setq (t0 t1)
810 (two-sum p4 q2))
812 (incf t1 (cl:+ p5 q3))
814 (multiple-value-setq (p3 p4)
815 (two-sum p3 t0))
816 (incf p4 (cl:+ q0 t1))
818 (multiple-value-call #'%make-qd-d
819 (renorm-5 p0 p1 p2 p3 p4))))))))))
822 #-cmu
823 (defun div-qd (a b)
824 (declare (type %quad-double a b)
825 (optimize (speed 3)
826 (space 0)))
827 (let ((a0 (qd-0 a))
828 (b0 (qd-0 b)))
829 (let* ((q0 (cl:/ a0 b0))
830 (r (sub-qd a (mul-qd-d b q0)))
831 (q1 (cl:/ (qd-0 r) b0)))
832 #+cmu
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)))))))
843 (defun div-qd (a b)
844 (declare (type %quad-double a b)
845 (optimize (speed 3)
846 (space 0)))
847 (let ((a0 (qd-0 a))
848 (b0 (qd-0 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)))))))
862 ;; Non-sloppy divide
863 #+(or)
864 (defun div-qd (a b)
865 (declare (type %quad-double a b))
866 (let ((a0 (qd-0 a))
867 (b0 (qd-0 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)
884 (double-float b)
885 (optimize (speed 3)
886 (space 0)))
887 ;; Compute approximate quotient using high order doubles, then
888 ;; correct it 3 times using the remainder. Analogous to long
889 ;; division.
890 (let ((q0 (cl:/ (qd-0 a) b)))
891 #+cmu
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)
897 (two-prod q0 b)
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))))
900 ;; First correction
901 (let ((q1 (cl:/ (qd-0 r) b)))
902 (multiple-value-bind (t0 t1)
903 (two-prod q1 b)
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)))
906 ;; Second correction
907 (let ((q2 (cl:/ (qd-0 r) b)))
908 (multiple-value-bind (t0 t1)
909 (two-prod q2 b)
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)))
912 ;; Final correction
913 (let ((q3 (cl:/ (qd-0 r) b)))
914 (make-qd-d q0 q1 q2 q3))))))))))
916 ;; Sloppy version
917 #+cmu
918 (defun div-qd-dd (a b)
919 (declare (type %quad-double a)
920 (double-double-float b)
921 (optimize (speed 3)
922 (space 0)))
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))))))
934 #+cmu
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))
948 (defun abs-qd (a)
949 (declare (type %quad-double a))
950 (if (minusp (float-sign (qd-0 a)))
951 (neg-qd a)
954 ;; a^n for an integer n
955 (defun npow (a n)
956 (declare (type %quad-double a)
957 (fixnum n)
958 (optimize (speed 3)
959 (space 0)))
960 (when (= n 0)
961 (return-from npow (make-qd-d 1d0)))
963 (let ((r a)
964 (s (make-qd-d 1d0))
965 (abs-n (abs n)))
966 (declare (type (and fixnum unsigned-byte) abs-n)
967 (type %quad-double r s))
968 (cond ((> abs-n 1)
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))
975 (when (plusp abs-n)
976 (setf r (sqr-qd r)))))
978 (setf s r)))
979 (if (minusp n)
980 (div-qd (make-qd-d 1d0) s)
981 s)))
983 ;; The n'th root of a. n is an positive integer and a should be
984 ;; positive too.
985 (defun nroot-qd (a n)
986 (declare (type %quad-double a)
987 (type (and fixnum unsigned-byte) n)
988 (optimize (speed 3)
989 (space 0)))
990 ;; Use Newton's iteration to solve
992 ;; 1/(x^n) - a = 0
994 ;; The iteration becomes
996 ;; x' = x + x * (1 - a * x^n)/n
998 ;; Since Newton's iteration converges quadratically, we only need to
999 ;; perform it twice.
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))
1003 (flet ((term ()
1004 (div-qd-d (mul-qd r
1005 (add-qd-d (neg-qd (mul-qd a (npow r n)))
1006 1d0))
1007 (float n 1d0))))
1008 (dotimes (k 3)
1009 (setf r (add-qd r (term))))
1010 (div-qd (make-qd-d 1d0) r))))
1012 (defun qd-< (a b)
1013 "A < B"
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)))))))))
1022 (defun qd-> (a b)
1023 "A > 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)))))))))
1032 (defun qd-<= (a b)
1033 "A > B"
1034 (not (qd-> a b)))
1036 (defun qd->= (a b)
1037 "A > B"
1038 (not (qd-< a b)))
1040 (defun zerop-qd (a)
1041 "Is A zero?"
1042 (declare (type %quad-double a))
1043 (zerop (qd-0 a)))
1045 (defun onep-qd (a)
1046 "Is A equal to 1?"
1047 (declare (type %quad-double a))
1048 (and (= (qd-0 a) 1d0)
1049 (zerop (qd-1 a))
1050 (zerop (qd-2 a))
1051 (zerop (qd-3 a))))
1053 (defun plusp-qd (a)
1054 "Is A positive?"
1055 (declare (type %quad-double a))
1056 (plusp (qd-0 a)))
1058 (defun minusp-qd (a)
1059 "Is A negative?"
1060 (declare (type %quad-double a))
1061 (minusp (qd-0 a)))
1063 (defun qd-= (a b)
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))))
1070 #+nil
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)))
1081 lo-exp
1082 sign)))))
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
1094 ;; is -1075.
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)))
1110 q3-exp
1111 q0-sign))))))
1113 (declaim (inline scale-float-qd))
1114 (defun scale-float-qd (qd k)
1115 (declare (type %quad-double qd)
1116 (type fixnum k)
1117 (optimize (speed 3) (space 0)))
1118 ;; (space 0) to get scale-double-float inlined
1119 (multiple-value-bind (a0 a1 a2 a3)
1120 (qd-parts qd)
1121 (make-qd-d (scale-float a0 k)
1122 (scale-float a1 k)
1123 (scale-float a2 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.
1129 #+(or)
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))
1149 (make-qd-d sign))))