Raymond Toy pushed to branch issue-459-more-accurate-dd-complex-div at cmucl / cmucl

Commits:

2 changed files:

Changes:

  • src/code/exports.lisp
    ... ... @@ -1670,7 +1670,6 @@
    1670 1670
     	   "TRUST-DYNAMIC-EXTENT-DECLARATION-P"
    
    1671 1671
     	   "IR2-STACK-ALLOCATE"
    
    1672 1672
     	   "%DYNAMIC-EXTENT" "%DYNAMIC-EXTENT-START" "%DYNAMIC-EXTENT-END")
    
    1673
    -  (:export "CDIV-DOUBLE-DOUBLE-FLOAT")
    
    1674 1673
       )
    
    1675 1674
     (defpackage "XREF"
    
    1676 1675
       (:export "INIT-XREF-DATABASE"
    
    ... ... @@ -1920,8 +1919,6 @@
    1920 1919
       (:import-from "LISP" "BOOLEAN")
    
    1921 1920
       (:import-from "C-CALL" "VOID")
    
    1922 1921
       (:import-from "CONDITIONS" "PARSE-UNKNOWN-TYPE-SPECIFIER")
    
    1923
    -  #+double-double
    
    1924
    -  (:import-from "C" "CDIV-DOUBLE-DOUBLE-FLOAT")
    
    1925 1922
       (:shadow "CLASS" "STRUCTURE-CLASS" "BUILT-IN-CLASS" "STANDARD-CLASS"
    
    1926 1923
                "FIND-CLASS" "CLASS-OF")
    
    1927 1924
       (:export "%CLASS-LAYOUT" "%CLASS-STATE" "%CLASS-DIRECT-SUPERCLASSES"
    

  • src/compiler/float-tran-dd.lisp
    ... ... @@ -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))