| ... |
... |
@@ -692,169 +692,6 @@ |
|
692
|
692
|
(kernel:double-double-hi b)
|
|
693
|
693
|
(kernel:double-double-lo b)))
|
|
694
|
694
|
|
|
695
|
|
-;; An implementation of Baudin and Smith's robust complex division for
|
|
696
|
|
-;; double-floats. This is a pretty straightforward translation of the
|
|
697
|
|
-;; original in https://arxiv.org/pdf/1210.4539.
|
|
698
|
|
-;;
|
|
699
|
|
-;; This also includes improvements mentioned in
|
|
700
|
|
-;; https://lpc.events/event/11/contributions/1005/attachments/856/1625/Complex_divide.pdf.
|
|
701
|
|
-;; In particular iteration 1 and 3 are added. Iteration 2 and 4 were
|
|
702
|
|
-;; not added. The test examples from iteration 2 and 4 didn't change
|
|
703
|
|
-;; with or without changes added.
|
|
704
|
|
-;;
|
|
705
|
|
-;; This is a pretty straightforward change of
|
|
706
|
|
-;; kernel::cdiv-double-float for double-double-float. The constants
|
|
707
|
|
-;; may need some tweaking.
|
|
708
|
|
-#+nil
|
|
709
|
|
-(let* ((+dd-eps+ (scale-float 1w0 -104))
|
|
710
|
|
- (+dd-rmin+ least-positive-normalized-double-double-float)
|
|
711
|
|
- (+dd-rbig+ (/ most-positive-double-double-float 2))
|
|
712
|
|
- (+dd-rmin2+ (scale-float 1w0 -105))
|
|
713
|
|
- (+dd-rminscal+ (scale-float 1w0 102))
|
|
714
|
|
- (+dd-rmax2+ (* +dd-rbig+ +dd-rmin2+))
|
|
715
|
|
- (+dd-be+ (/ 2 (* +dd-eps+ +dd-eps+)))
|
|
716
|
|
- (+dd-2/eps+ (/ 2 +dd-eps+)))
|
|
717
|
|
- (declare (double-double-float +dd-eps+ +dd-rmin+ +dd-rbig+ +dd-rmin2+
|
|
718
|
|
- +dd-rminscal+ +dd-rmax2+ +dd-be+ +dd-2/eps+))
|
|
719
|
|
- (defun cdiv-double-double-float (x y)
|
|
720
|
|
- (declare (type (complex double-double-float) x y)
|
|
721
|
|
- (optimize (speed 2) (safety 0)))
|
|
722
|
|
- (labels
|
|
723
|
|
- ((internal-compreal (a b c d r tt)
|
|
724
|
|
- (declare (double-double-float a b c d r tt))
|
|
725
|
|
- ;; Compute the real part of the complex division
|
|
726
|
|
- ;; (a+ib)/(c+id), assuming |c| <= |d|. r = d/c and tt = 1/(c+d*r).
|
|
727
|
|
- ;;
|
|
728
|
|
- ;; The realpart is (a*c+b*d)/(c^2+d^2).
|
|
729
|
|
- ;;
|
|
730
|
|
- ;; c^2+d^2 = c*(c+d*(d/c)) = c*(c+d*r)
|
|
731
|
|
- ;;
|
|
732
|
|
- ;; Then
|
|
733
|
|
- ;;
|
|
734
|
|
- ;; (a*c+b*d)/(c^2+d^2) = (a*c+b*d)/(c*(c+d*r))
|
|
735
|
|
- ;; = (a + b*d/c)/(c+d*r)
|
|
736
|
|
- ;; = (a + b*r)/(c + d*r).
|
|
737
|
|
- ;;
|
|
738
|
|
- ;; Thus tt = (c + d*r).
|
|
739
|
|
- (cond ((>= (abs r) +dd-rmin+)
|
|
740
|
|
- (let ((br (* b r)))
|
|
741
|
|
- (if (/= br 0)
|
|
742
|
|
- (/ (+ a br) tt)
|
|
743
|
|
- ;; b*r underflows. Instead, compute
|
|
744
|
|
- ;;
|
|
745
|
|
- ;; (a + b*r)*tt = a*tt + b*tt*r
|
|
746
|
|
- ;; = a*tt + (b*tt)*r
|
|
747
|
|
- ;; (a + b*r)/tt = a/tt + b/tt*r
|
|
748
|
|
- ;; = a*tt + (b*tt)*r
|
|
749
|
|
- (+ (/ a tt)
|
|
750
|
|
- (* (/ b tt)
|
|
751
|
|
- r)))))
|
|
752
|
|
- (t
|
|
753
|
|
- ;; r = 0 so d is very tiny compared to c.
|
|
754
|
|
- ;;
|
|
755
|
|
- (/ (+ a (* d (/ b c)))
|
|
756
|
|
- tt))))
|
|
757
|
|
- (robust-subinternal (a b c d)
|
|
758
|
|
- (declare (double-double-float a b c d))
|
|
759
|
|
- (let* ((r (/ d c))
|
|
760
|
|
- (tt (+ c (* d r))))
|
|
761
|
|
- ;; e is the real part and f is the imaginary part. We
|
|
762
|
|
- ;; can use internal-compreal for the imaginary part by
|
|
763
|
|
- ;; noticing that the imaginary part of (a+i*b)/(c+i*d) is
|
|
764
|
|
- ;; the same as the real part of (b-i*a)/(c+i*d).
|
|
765
|
|
- (let ((e (internal-compreal a b c d r tt))
|
|
766
|
|
- (f (internal-compreal b (- a) c d r tt)))
|
|
767
|
|
- (values e
|
|
768
|
|
- f))))
|
|
769
|
|
-
|
|
770
|
|
- (robust-internal (x y)
|
|
771
|
|
- (declare (type (complex double-double-float) x y))
|
|
772
|
|
- (let ((a (realpart x))
|
|
773
|
|
- (b (imagpart x))
|
|
774
|
|
- (c (realpart y))
|
|
775
|
|
- (d (imagpart y)))
|
|
776
|
|
- (declare (double-double-float a b c d))
|
|
777
|
|
- (flet ((maybe-scale (abs-tst a b c d)
|
|
778
|
|
- (declare (double-double-float a b c d))
|
|
779
|
|
- ;; This implements McGehearty's iteration 3 to
|
|
780
|
|
- ;; handle the case when some values are too big
|
|
781
|
|
- ;; and should be scaled down. Also if some
|
|
782
|
|
- ;; values are too tiny, scale them up.
|
|
783
|
|
- (let ((abs-a (abs a))
|
|
784
|
|
- (abs-b (abs b)))
|
|
785
|
|
- (if (or (> abs-tst +dd-rbig+)
|
|
786
|
|
- (> abs-a +dd-rbig+)
|
|
787
|
|
- (> abs-b +dd-rbig+))
|
|
788
|
|
- (setf a (* a 0.5d0)
|
|
789
|
|
- b (* b 0.5d0)
|
|
790
|
|
- c (* c 0.5d0)
|
|
791
|
|
- d (* d 0.5d0))
|
|
792
|
|
- (if (< abs-tst +dd-rmin2+)
|
|
793
|
|
- (setf a (* a +dd-rminscal+)
|
|
794
|
|
- b (* b +dd-rminscal+)
|
|
795
|
|
- c (* c +dd-rminscal+)
|
|
796
|
|
- d (* d +dd-rminscal+))
|
|
797
|
|
- (if (or (and (< abs-a +dd-rmin+)
|
|
798
|
|
- (< abs-b +dd-rmax2+)
|
|
799
|
|
- (< abs-tst +dd-rmax2+))
|
|
800
|
|
- (and (< abs-b +dd-rmin+)
|
|
801
|
|
- (< abs-a +dd-rmax2+)
|
|
802
|
|
- (< abs-tst +dd-rmax2+)))
|
|
803
|
|
- (setf a (* a +dd-rminscal+)
|
|
804
|
|
- b (* b +dd-rminscal+)
|
|
805
|
|
- c (* c +dd-rminscal+)
|
|
806
|
|
- d (* d +dd-rminscal+)))))
|
|
807
|
|
- (values a b c d))))
|
|
808
|
|
- (cond
|
|
809
|
|
- ((<= (abs d) (abs c))
|
|
810
|
|
- ;; |d| <= |c|, so we can use robust-subinternal to
|
|
811
|
|
- ;; perform the division.
|
|
812
|
|
- (multiple-value-bind (a b c d)
|
|
813
|
|
- (maybe-scale (abs c) a b c d)
|
|
814
|
|
- (multiple-value-bind (e f)
|
|
815
|
|
- (robust-subinternal a b c d)
|
|
816
|
|
- (complex e f))))
|
|
817
|
|
- (t
|
|
818
|
|
- ;; |d| > |c|. So, instead compute
|
|
819
|
|
- ;;
|
|
820
|
|
- ;; (b + i*a)/(d + i*c) = ((b*d+a*c) + (a*d-b*c)*i)/(d^2+c^2)
|
|
821
|
|
- ;;
|
|
822
|
|
- ;; Compare this to (a+i*b)/(c+i*d) and we see that
|
|
823
|
|
- ;; realpart of the former is the same, but the
|
|
824
|
|
- ;; imagpart of the former is the negative of the
|
|
825
|
|
- ;; desired division.
|
|
826
|
|
- (multiple-value-bind (a b c d)
|
|
827
|
|
- (maybe-scale (abs d) a b c d)
|
|
828
|
|
- (multiple-value-bind (e f)
|
|
829
|
|
- (robust-subinternal b a d c)
|
|
830
|
|
- (complex e (- f))))))))))
|
|
831
|
|
- (let* ((a (realpart x))
|
|
832
|
|
- (b (imagpart x))
|
|
833
|
|
- (c (realpart y))
|
|
834
|
|
- (d (imagpart y))
|
|
835
|
|
- (ab (max (abs a) (abs b)))
|
|
836
|
|
- (cd (max (abs c) (abs d)))
|
|
837
|
|
- (s 1w0))
|
|
838
|
|
- (declare (double-double-float s))
|
|
839
|
|
- ;; If a or b is big, scale down a and b.
|
|
840
|
|
- (when (>= ab +dd-rbig+)
|
|
841
|
|
- (setf x (/ x 2)
|
|
842
|
|
- s (* s 2)))
|
|
843
|
|
- ;; If c or d is big, scale down c and d.
|
|
844
|
|
- (when (>= cd +dd-rbig+)
|
|
845
|
|
- (setf y (/ y 2)
|
|
846
|
|
- s (/ s 2)))
|
|
847
|
|
- ;; If a or b is tiny, scale up a and b.
|
|
848
|
|
- (when (<= ab (* +dd-rmin+ +dd-2/eps+))
|
|
849
|
|
- (setf x (* x +dd-be+)
|
|
850
|
|
- s (/ s +dd-be+)))
|
|
851
|
|
- ;; If c or d is tiny, scale up c and d.
|
|
852
|
|
- (when (<= cd (* +dd-rmin+ +dd-2/eps+))
|
|
853
|
|
- (setf y (* y +dd-be+)
|
|
854
|
|
- s (* s +dd-be+)))
|
|
855
|
|
- (* s
|
|
856
|
|
- (robust-internal x y))))))
|
|
857
|
|
-
|
|
858
|
695
|
(deftransform / ((x y) ((complex double-double-float) (complex double-double-float))
|
|
859
|
696
|
*)
|
|
860
|
697
|
`(kernel::cdiv-double-double-float x y))
|