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

Commits:

1 changed file:

Changes:

  • src/code/numbers.lisp
    ... ... @@ -612,25 +612,33 @@
    612 612
     (defconstant +cdiv-be+ (/ 2 (* +cdiv-eps+ +cdiv-eps+)))
    
    613 613
     (defconstant +cdiv-2/eps+ (/ 2 +cdiv-eps+))
    
    614 614
     
    
    615
    -;; Same constants but for double-double-floats.  Some of these aren't
    
    616
    -;; well-defined for double-double-floats so we make our best guess at
    
    615
    +;; Same constants but for DOUBLE-DOUBLE-FLOATS.  Some of these aren't
    
    616
    +;; well-defined for DOUBLE-DOUBLE-FLOATS so we make our best guess at
    
    617 617
     ;; what they might be.  Since double-doubles have about twice as many
    
    618
    -;; bits of precision as a double-float, we generally just double the
    
    619
    -;; exponent of the corresponding double-float values above.
    
    618
    +;; bits of precision as a DOUBLE-FLOAT, we generally just double the
    
    619
    +;; exponent (for SCALE-FLOAT) of the corresponding DOUBLE-FLOAT values
    
    620
    +;; above.
    
    621
    +;;
    
    622
    +;; Note also that both LEAST-POSITIVE-NORMALIZED-DOUBLE-DOUBLE-FLOAT
    
    623
    +;; and MOST-POSITIVE-DOUBLE-DOUBLE-FLOAT have a low component of 0, so
    
    624
    +;; there's no loss of precision if we use the corresponding
    
    625
    +;; DOUBLE-FLOAT values.  Likewise, all the other constants here are
    
    626
    +;; powers of 2, so the DOUBLE-DOUBLE-FLOAT values can be represented
    
    627
    +;; exactly as a DOUBLE-FLOAT.  We can use DOUBLE-FLOAT values.
    
    620 628
     (defconstant +cdiv-dd-rmin+
    
    621
    -  least-positive-normalized-double-double-float)
    
    629
    +  least-positive-normalized-double-float)
    
    622 630
     (defconstant +cdiv-dd-rbig+
    
    623
    -  (/ most-positive-double-double-float 2))
    
    631
    +  (/ most-positive-double-float 2))
    
    624 632
     (defconstant +cdiv-dd-rmin2+
    
    625
    -  (scale-float 1w0 -106))
    
    633
    +  (scale-float 1d0 -106))
    
    626 634
     (defconstant +cdiv-dd-rminscal+
    
    627
    -  (scale-float 1w0 102))
    
    635
    +  (scale-float 1d0 102))
    
    628 636
     (defconstant +cdiv-dd-rmax2+
    
    629 637
       (* +cdiv-dd-rbig+ +cdiv-dd-rmin2+))
    
    630 638
     ;; Epsilon for double-doubles isn't really well-defined because things
    
    631 639
     ;; like (+ 1w0 1w-200) is a valid double-double float.
    
    632 640
     (defconstant +cdiv-dd-eps+
    
    633
    -  (scale-float 1w0 -104))
    
    641
    +  (scale-float 1d0 -104))
    
    634 642
     (defconstant +cdiv-dd-be+
    
    635 643
       (/ 2 (* +cdiv-dd-eps+ +cdiv-dd-eps+)))
    
    636 644
     (defconstant +cdiv-dd-2/eps+
    
    ... ... @@ -643,179 +651,11 @@
    643 651
     ;; else.
    
    644 652
     (declaim (ext:start-block cdiv-double-float cdiv-single-float
    
    645 653
     			  cdiv-double-double-float
    
    646
    -			  two-arg-/
    
    647
    -			  cdiv-double-float-internal-compreal
    
    648
    -			  cdiv-double-float-robust-subinternal
    
    649
    -			  cdiv-double-float-robust-internal
    
    650
    -			  cdiv-double-double-float-internal-compreal
    
    651
    -			  cdiv-double-double-float-robust-subinternal
    
    652
    -			  cdiv-double-double-float-robust-internal))
    
    654
    +			  two-arg-/))
    
    653 655
     
    
    654 656
     ;; The code for both the double-float and double-double-float
    
    655 657
     ;; implementation is basically identical except for the constants.
    
    656 658
     ;; use a macro to generate both versions.
    
    657
    -#+nil
    
    658
    -(macrolet
    
    659
    -    ((frob (type)
    
    660
    -       (let* ((dd (if (eq type 'double-float)
    
    661
    -		      ""
    
    662
    -		      "DD-"))
    
    663
    -	      (name (symbolicate "CDIV-" type))
    
    664
    -	      (docstring (let ((*print-case* :downcase))
    
    665
    -			   (format nil "Accurate division of complex ~A numbers x and y."
    
    666
    -				   type)))
    
    667
    -	      ;; Create the correct symbols for the constants we need,
    
    668
    -	      ;; as defined above.
    
    669
    -	      (+rmin+ (symbolicate "+CDIV-" dd "RMIN+"))
    
    670
    -	      (+rbig+ (symbolicate "+CDIV-" dd "RBIG+"))
    
    671
    -	      (+rmin2+ (symbolicate "+CDIV-" dd "RMIN2+"))
    
    672
    -	      (+rminscal+ (symbolicate "+CDIV-" dd "RMINSCAL+"))
    
    673
    -	      (+rmax2+ (symbolicate "+CDIV-" dd "RMAX2+"))
    
    674
    -	      (+eps+ (symbolicate "+CDIV-" dd "EPS+"))
    
    675
    -	      (+be+ (symbolicate "+CDIV-" dd "BE+"))
    
    676
    -	      (+2/eps+ (symbolicate "+CDIV-" dd "2/EPS+")))
    
    677
    -	 `(defun ,name (x y)
    
    678
    -	    ,docstring
    
    679
    -	    (declare (type (complex ,type) x y)
    
    680
    -		     (optimize (speed 3) (safety 0)))
    
    681
    -	    (labels
    
    682
    -		((internal-compreal (a b c d r tt)
    
    683
    -		   (declare (,type a b c d r tt))
    
    684
    -		   ;; Compute the real part of the complex division
    
    685
    -		   ;; (a+ib)/(c+id), assuming |c| <= |d|.  r = d/c and tt = 1/(c+d*r).
    
    686
    -		   ;;
    
    687
    -		   ;; The realpart is (a*c+b*d)/(c^2+d^2).
    
    688
    -		   ;;
    
    689
    -		   ;;   c^2+d^2 = c*(c+d*(d/c)) = c*(c+d*r)
    
    690
    -		   ;;
    
    691
    -		   ;; Then
    
    692
    -		   ;;
    
    693
    -		   ;;   (a*c+b*d)/(c^2+d^2) = (a*c+b*d)/(c*(c+d*r))
    
    694
    -		   ;;                       = (a + b*d/c)/(c+d*r)
    
    695
    -		   ;;                       = (a + b*r)/(c + d*r).
    
    696
    -		   ;;
    
    697
    -		   ;; Thus tt = (c + d*r).
    
    698
    -		   (cond ((>= (abs r) ,+rmin+)
    
    699
    -			  (let ((br (* b r)))
    
    700
    -			    (if (/= br 0)
    
    701
    -				(/ (+ a br) tt)
    
    702
    -				;; b*r underflows.  Instead, compute
    
    703
    -				;;
    
    704
    -				;; (a + b*r)*tt = a*tt + b*tt*r
    
    705
    -				;;              = a*tt + (b*tt)*r
    
    706
    -				;; (a + b*r)/tt = a/tt + b/tt*r
    
    707
    -				;;              = a*tt + (b*tt)*r
    
    708
    -				(+ (/ a tt)
    
    709
    -				   (* (/ b tt)
    
    710
    -				      r)))))
    
    711
    -			 (t
    
    712
    -			  ;; r = 0 so d is very tiny compared to c.
    
    713
    -			  ;;
    
    714
    -			  (/ (+ a (* d (/ b c)))
    
    715
    -			     tt))))
    
    716
    -		 (robust-subinternal (a b c d)
    
    717
    -		   (declare (,type a b c d))
    
    718
    -		   (let* ((r (/ d c))
    
    719
    -			  (tt (+ c (* d r))))
    
    720
    -		     ;; e is the real part and f is the imaginary part.  We
    
    721
    -		     ;; can use internal-compreal for the imaginary part by
    
    722
    -		     ;; noticing that the imaginary part of (a+i*b)/(c+i*d) is
    
    723
    -		     ;; the same as the real part of (b-i*a)/(c+i*d).
    
    724
    -		     (let ((e (internal-compreal a b c d r tt))
    
    725
    -			   (f (internal-compreal b (- a) c d r tt)))
    
    726
    -		       (values e
    
    727
    -			       f))))
    
    728
    -		 (robust-internal (x y)
    
    729
    -		   (declare (type (complex ,type) x y))
    
    730
    -		   (let ((a (realpart x))
    
    731
    -			 (b (imagpart x))
    
    732
    -			 (c (realpart y))
    
    733
    -			 (d (imagpart y)))
    
    734
    -		     (declare (,type a b c d))
    
    735
    -		     (flet ((maybe-scale (abs-tst a b c d)
    
    736
    -			      (declare (,type a b c d))
    
    737
    -			      ;; This implements McGehearty's iteration 3 to
    
    738
    -			      ;; handle the case when some values are too big
    
    739
    -			      ;; and should be scaled down.  Also if some
    
    740
    -			      ;; values are too tiny, scale them up.
    
    741
    -			      (let ((abs-a (abs a))
    
    742
    -				    (abs-b (abs b)))
    
    743
    -				(if (or (> abs-tst ,+rbig+)
    
    744
    -					(> abs-a ,+rbig+)
    
    745
    -					(> abs-b ,+rbig+))
    
    746
    -				    (setf a (* a 0.5d0)
    
    747
    -					  b (* b 0.5d0)
    
    748
    -					  c (* c 0.5d0)
    
    749
    -					  d (* d 0.5d0))
    
    750
    -				    (if (< abs-tst ,+rmin2+)
    
    751
    -					(setf a (* a ,+rminscal+)
    
    752
    -					      b (* b ,+rminscal+)
    
    753
    -					      c (* c ,+rminscal+)
    
    754
    -					      d (* d ,+rminscal+))
    
    755
    -					(if (or (and (< abs-a ,+rmin+)
    
    756
    -						     (< abs-b ,+rmax2+)
    
    757
    -						     (< abs-tst ,+rmax2+))
    
    758
    -						(and (< abs-b ,+rmin+)
    
    759
    -						     (< abs-a ,+rmax2+)
    
    760
    -						     (< abs-tst ,+rmax2+)))
    
    761
    -					    (setf a (* a ,+rminscal+)
    
    762
    -						  b (* b ,+rminscal+)
    
    763
    -						  c (* c ,+rminscal+)
    
    764
    -						  d (* d ,+rminscal+)))))
    
    765
    -				(values a b c d))))
    
    766
    -		       (cond
    
    767
    -			 ((<= (abs d) (abs c))
    
    768
    -			  ;; |d| <= |c|, so we can use robust-subinternal to
    
    769
    -			  ;; perform the division.
    
    770
    -			  (multiple-value-bind (a b c d)
    
    771
    -			      (maybe-scale (abs c) a b c d)
    
    772
    -			    (multiple-value-bind (e f)
    
    773
    -				(robust-subinternal a b c d)
    
    774
    -			      (complex e f))))
    
    775
    -			 (t
    
    776
    -			  ;; |d| > |c|.  So, instead compute
    
    777
    -			  ;;
    
    778
    -			  ;;   (b + i*a)/(d + i*c) = ((b*d+a*c) + (a*d-b*c)*i)/(d^2+c^2)
    
    779
    -			  ;;
    
    780
    -			  ;; Compare this to (a+i*b)/(c+i*d) and we see that
    
    781
    -			  ;; realpart of the former is the same, but the
    
    782
    -			  ;; imagpart of the former is the negative of the
    
    783
    -			  ;; desired division.
    
    784
    -			  (multiple-value-bind (a b c d)
    
    785
    -			      (maybe-scale (abs d) a b c d)
    
    786
    -			    (multiple-value-bind (e f)
    
    787
    -				(robust-subinternal b a d c)
    
    788
    -			      (complex e (- f))))))))))
    
    789
    -	      (let* ((a (realpart x))
    
    790
    -		     (b (imagpart x))
    
    791
    -		     (c (realpart y))
    
    792
    -		     (d (imagpart y))
    
    793
    -		     (ab (max (abs a) (abs b)))
    
    794
    -		     (cd (max (abs c) (abs d)))
    
    795
    -		     (s (coerce 1 ',type)))
    
    796
    -		(declare (,type s))
    
    797
    -		;; If a or b is big, scale down a and b.
    
    798
    -		(when (>= ab ,+rbig+)
    
    799
    -		  (setf x (* x 0.5d0)
    
    800
    -			s (* s 2)))
    
    801
    -		;; If c or d is big, scale down c and d.
    
    802
    -		(when (>= cd ,+rbig+)
    
    803
    -		  (setf y (* y 0.5d0)
    
    804
    -			s (* s 0.5d0)))
    
    805
    -		;; If a or b is tiny, scale up a and b.
    
    806
    -		(when (<= ab (* ,+rmin+ ,+2/eps+))
    
    807
    -		  (setf x (* x ,+be+)
    
    808
    -			s (/ s ,+be+)))
    
    809
    -		;; If c or d is tiny, scale up c and d.
    
    810
    -		(when (<= cd (* ,+rmin+ ,+2/eps+))
    
    811
    -		  (setf y (* y ,+be+)
    
    812
    -			s (* s ,+be+)))
    
    813
    -		(* s
    
    814
    -		   (robust-internal x y))))))))
    
    815
    -  (frob double-float)
    
    816
    -  #+double-double
    
    817
    -  (frob double-double-float))
    
    818
    -
    
    819 659
     (eval-when (:compile-toplevel)
    
    820 660
     (defmacro define-cdiv (type)
    
    821 661
       (let* ((dd (if (eq type 'double-float)
    
    ... ... @@ -842,11 +682,14 @@
    842 682
            (defun ,compreal (a b c d r tt)
    
    843 683
     	 (declare (,type a b c d r tt)
    
    844 684
     		  ,@opt)
    
    845
    -	 ;; Compute the real part of the complex division
    
    846
    -	 ;; (a+ib)/(c+id), assuming |c| <= |d|.  r = d/c and tt = 1/(c+d*r).
    
    685
    +	 ;; Computes the real part of the complex division
    
    686
    +	 ;; (a+ib)/(c+id), assuming |d| <= |c|.  Then let r = d/c and
    
    687
    +	 ;; tt = (c+d*r).
    
    847 688
     	 ;;
    
    848 689
     	 ;; The realpart is (a*c+b*d)/(c^2+d^2).
    
    849 690
     	 ;;
    
    691
    +	 ;; The denominator is
    
    692
    +	 ;;
    
    850 693
     	 ;;   c^2+d^2 = c*(c+d*(d/c)) = c*(c+d*r)
    
    851 694
     	 ;;
    
    852 695
     	 ;; Then
    
    ... ... @@ -862,15 +705,12 @@
    862 705
     		      (/ (+ a br) tt)
    
    863 706
     		      ;; b*r underflows.  Instead, compute
    
    864 707
     		      ;;
    
    865
    -		      ;; (a + b*r)*tt = a*tt + b*tt*r
    
    866
    -		      ;;              = a*tt + (b*tt)*r
    
    867 708
     		      ;; (a + b*r)/tt = a/tt + b/tt*r
    
    868
    -		      ;;              = a*tt + (b*tt)*r
    
    869 709
     		      (+ (/ a tt)
    
    870 710
     			 (* (/ b tt)
    
    871 711
     			    r)))))
    
    872 712
     	       (t
    
    873
    -		;; r = 0 so d is very tiny compared to c.
    
    713
    +		;; r is very small so d is very tiny compared to c.
    
    874 714
     		;;
    
    875 715
     		(/ (+ a (* d (/ b c)))
    
    876 716
     		   tt))))
    
    ... ... @@ -931,9 +771,7 @@
    931 771
     		;; perform the division.
    
    932 772
     		(multiple-value-bind (a b c d)
    
    933 773
     		    (maybe-scale (abs c) a b c d)
    
    934
    -		  (multiple-value-bind (e f)
    
    935
    -		      (,subinternal a b c d)
    
    936
    -		    (complex e f))))
    
    774
    +		  (,subinternal a b c d)))
    
    937 775
     	       (t
    
    938 776
     		;; |d| > |c|.  So, instead compute
    
    939 777
     		;;
    
    ... ... @@ -947,7 +785,7 @@
    947 785
     		    (maybe-scale (abs d) a b c d)
    
    948 786
     		  (multiple-value-bind (e f)
    
    949 787
     		      (,subinternal b a d c)
    
    950
    -		    (complex e (- f)))))))))
    
    788
    +		    (values e (- f)))))))))
    
    951 789
            (defun ,name (x y)
    
    952 790
     	 ,docstring
    
    953 791
     	 (declare (type (complex ,type) x y)
    
    ... ... @@ -982,14 +820,15 @@
    982 820
     	   (when (<= cd (* ,+rmin+ ,+2/eps+))
    
    983 821
     	     (setf y (* y ,+be+)
    
    984 822
     		   s (* s ,+be+)))
    
    985
    -	   (* s
    
    986
    -	      (,internal x y)))))))
    
    823
    +	   (multiple-value-bind (e f)
    
    824
    +	       (,internal x y)
    
    825
    +	     (complex (* s e)
    
    826
    +		      (* s f))))))))
    
    987 827
     )
    
    988 828
     
    
    989 829
     (define-cdiv double-float)
    
    990 830
     (define-cdiv double-double-float)
    
    991 831
     
    
    992
    -
    
    993 832
     ;; Smith's algorithm for complex division for (complex single-float).
    
    994 833
     ;; We convert the parts to double-floats before computing the result.
    
    995 834
     (defun cdiv-single-float (x y)