Raymond Toy pushed to branch master at cmucl / cmucl

Commits:

4 changed files:

Changes:

  • src/code/numbers.lisp
    ... ... @@ -593,26 +593,250 @@
    593 593
     	    (build-ratio x y)
    
    594 594
     	    (build-ratio (truncate x gcd) (truncate y gcd))))))
    
    595 595
     
    
    596
    +;; An implementation of Baudin and Smith's robust complex division for
    
    597
    +;; double-floats.  This is a pretty straightforward translation of the
    
    598
    +;; original in https://arxiv.org/pdf/1210.4539.
    
    599
    +;;
    
    600
    +;; This also includes improvements mentioned in
    
    601
    +;; https://lpc.events/event/11/contributions/1005/attachments/856/1625/Complex_divide.pdf.
    
    602
    +;; In particular iteration 1 and 3 are added.  Iteration 2 and 4 were
    
    603
    +;; not added.  The test examples from iteration 2 and 4 didn't change
    
    604
    +;; with or without changes added.
    
    605
    +(defconstant +cdiv-rmin+ least-positive-normalized-double-float)
    
    606
    +(defconstant +cdiv-rbig+ (/ most-positive-double-float 2))
    
    607
    +(defconstant +cdiv-rmin2+ (scale-float 1d0 -53))
    
    608
    +(defconstant +cdiv-rminscal+ (scale-float 1d0 51))
    
    609
    +(defconstant +cdiv-rmax2+ (* +cdiv-rbig+ +cdiv-rmin2+))
    
    610
    +;; This is the value of %eps from Scilab
    
    611
    +(defconstant +cdiv-eps+ (scale-float 1d0 -52))
    
    612
    +(defconstant +cdiv-be+ (/ 2 (* +cdiv-eps+ +cdiv-eps+)))
    
    613
    +(defconstant +cdiv-2/eps+ (/ 2 +cdiv-eps+))
    
    614
    +
    
    615
    +;; Make these functions accessible.  cdiv-double-float and
    
    616
    +;; cdiv-single-float are used by deftransforms.  Of course, two-arg-/
    
    617
    +;; is the interface to division.  cdiv-generic isn't used anywhere
    
    618
    +;; else.
    
    619
    +(declaim (ext:start-block cdiv-double-float cdiv-single-float two-arg-/))
    
    620
    +
    
    621
    +(defun cdiv-double-float (x y)
    
    622
    +  "Accurate division of complex double-float numbers x and y."
    
    623
    +  (declare (type (complex double-float) x y)
    
    624
    +	   (optimize (speed 3) (safety 0)))
    
    625
    +  (labels
    
    626
    +      ((internal-compreal (a b c d r tt)
    
    627
    +	 (declare (double-float a b c d r tt))
    
    628
    +	 ;; Compute the real part of the complex division
    
    629
    +	 ;; (a+ib)/(c+id), assuming |c| <= |d|.  r = d/c and tt = 1/(c+d*r).
    
    630
    +	 ;;
    
    631
    +	 ;; The realpart is (a*c+b*d)/(c^2+d^2).
    
    632
    +	 ;;
    
    633
    +	 ;;   c^2+d^2 = c*(c+d*(d/c)) = c*(c+d*r)
    
    634
    +	 ;;
    
    635
    +	 ;; Then
    
    636
    +	 ;;
    
    637
    +	 ;;   (a*c+b*d)/(c^2+d^2) = (a*c+b*d)/(c*(c+d*r))
    
    638
    +	 ;;                       = (a + b*d/c)/(c+d*r)
    
    639
    +	 ;;                       = (a + b*r)/(c + d*r).
    
    640
    +	 ;;
    
    641
    +	 ;; Thus tt = (c + d*r).
    
    642
    +	 (cond ((>= (abs r) +cdiv-rmin+)
    
    643
    +		(let ((br (* b r)))
    
    644
    +		  (if (/= br 0)
    
    645
    +		      (/ (+ a br) tt)
    
    646
    +		      ;; b*r underflows.  Instead, compute
    
    647
    +		      ;;
    
    648
    +		      ;; (a + b*r)*tt = a*tt + b*tt*r
    
    649
    +		      ;;              = a*tt + (b*tt)*r
    
    650
    +		      ;; (a + b*r)/tt = a/tt + b/tt*r
    
    651
    +		      ;;              = a*tt + (b*tt)*r
    
    652
    +		      (+ (/ a tt)
    
    653
    +			 (* (/ b tt)
    
    654
    +			    r)))))
    
    655
    +	       (t
    
    656
    +		;; r = 0 so d is very tiny compared to c.
    
    657
    +		;;
    
    658
    +		(/ (+ a (* d (/ b c)))
    
    659
    +		   tt))))
    
    660
    +       (robust-subinternal (a b c d)
    
    661
    +	 (declare (double-float a b c d))
    
    662
    +	 (let* ((r (/ d c))
    
    663
    +		(tt (+ c (* d r))))
    
    664
    +	   ;; e is the real part and f is the imaginary part.  We
    
    665
    +	   ;; can use internal-compreal for the imaginary part by
    
    666
    +	   ;; noticing that the imaginary part of (a+i*b)/(c+i*d) is
    
    667
    +	   ;; the same as the real part of (b-i*a)/(c+i*d).
    
    668
    +	   (let ((e (internal-compreal a b c d r tt))
    
    669
    +		 (f (internal-compreal b (- a) c d r tt)))
    
    670
    +	     (values e
    
    671
    +		     f))))
    
    672
    +	 
    
    673
    +       (robust-internal (x y)
    
    674
    +	 (declare (type (complex double-float) x y))
    
    675
    +	 (let ((a (realpart x))
    
    676
    +	       (b (imagpart x))
    
    677
    +	       (c (realpart y))
    
    678
    +	       (d (imagpart y)))
    
    679
    +	   (declare (double-float a b c d))
    
    680
    +	   (flet ((maybe-scale (abs-tst a b c d)
    
    681
    +		    (declare (double-float a b c d))
    
    682
    +		    ;; This implements McGehearty's iteration 3 to
    
    683
    +		    ;; handle the case when some values are too big
    
    684
    +		    ;; and should be scaled down.  Also if some
    
    685
    +		    ;; values are too tiny, scale them up.
    
    686
    +		    (let ((abs-a (abs a))
    
    687
    +			  (abs-b (abs b)))
    
    688
    +		      (if (or (> abs-tst +cdiv-rbig+)
    
    689
    +			      (> abs-a +cdiv-rbig+)
    
    690
    +			      (> abs-b +cdiv-rbig+))
    
    691
    +			  (setf a (* a 0.5d0)
    
    692
    +				b (* b 0.5d0)
    
    693
    +				c (* c 0.5d0)
    
    694
    +				d (* d 0.5d0))
    
    695
    +			  (if (< abs-tst +cdiv-rmin2+)
    
    696
    +			      (setf a (* a +cdiv-rminscal+)
    
    697
    +				    b (* b +cdiv-rminscal+)
    
    698
    +				    c (* c +cdiv-rminscal+)
    
    699
    +				    d (* d +cdiv-rminscal+))
    
    700
    +			      (if (or (and (< abs-a +cdiv-rmin+)
    
    701
    +					   (< abs-b +cdiv-rmax2+)
    
    702
    +					   (< abs-tst +cdiv-rmax2+))
    
    703
    +				      (and (< abs-b +cdiv-rmin+)
    
    704
    +					   (< abs-a +cdiv-rmax2+)
    
    705
    +					   (< abs-tst +cdiv-rmax2+)))
    
    706
    +				  (setf a (* a +cdiv-rminscal+)
    
    707
    +					b (* b +cdiv-rminscal+)
    
    708
    +					c (* c +cdiv-rminscal+)
    
    709
    +					d (* d +cdiv-rminscal+)))))
    
    710
    +		      (values a b c d))))
    
    711
    +	     (cond
    
    712
    +	       ((<= (abs d) (abs c))
    
    713
    +		;; |d| <= |c|, so we can use robust-subinternal to
    
    714
    +		;; perform the division.
    
    715
    +		(multiple-value-bind (a b c d)
    
    716
    +		    (maybe-scale (abs c) a b c d)
    
    717
    +		  (multiple-value-bind (e f)
    
    718
    +		      (robust-subinternal a b c d)
    
    719
    +		    (complex e f))))
    
    720
    +	       (t
    
    721
    +		;; |d| > |c|.  So, instead compute
    
    722
    +		;;
    
    723
    +		;;   (b + i*a)/(d + i*c) = ((b*d+a*c) + (a*d-b*c)*i)/(d^2+c^2)
    
    724
    +		;;
    
    725
    +		;; Compare this to (a+i*b)/(c+i*d) and we see that
    
    726
    +		;; realpart of the former is the same, but the
    
    727
    +		;; imagpart of the former is the negative of the
    
    728
    +		;; desired division.
    
    729
    +		(multiple-value-bind (a b c d)
    
    730
    +		    (maybe-scale (abs d) a b c d)
    
    731
    +		  (multiple-value-bind (e f)
    
    732
    +		      (robust-subinternal b a d c)
    
    733
    +		    (complex e (- f))))))))))
    
    734
    +    (let* ((a (realpart x))
    
    735
    +	   (b (imagpart x))
    
    736
    +	   (c (realpart y))
    
    737
    +	   (d (imagpart y))
    
    738
    +	   (ab (max (abs a) (abs b)))
    
    739
    +	   (cd (max (abs c) (abs d)))
    
    740
    +	   (s 1d0))
    
    741
    +      (declare (double-float s))
    
    742
    +      ;; If a or b is big, scale down a and b.
    
    743
    +      (when (>= ab +cdiv-rbig+)
    
    744
    +	(setf x (/ x 2)
    
    745
    +	      s (* s 2)))
    
    746
    +      ;; If c or d is big, scale down c and d.
    
    747
    +      (when (>= cd +cdiv-rbig+)
    
    748
    +	(setf y (/ y 2)
    
    749
    +	      s (/ s 2)))
    
    750
    +      ;; If a or b is tiny, scale up a and b.
    
    751
    +      (when (<= ab (* +cdiv-rmin+ +cdiv-2/eps+))
    
    752
    +	(setf x (* x +cdiv-be+)
    
    753
    +	      s (/ s +cdiv-be+)))
    
    754
    +      ;; If c or d is tiny, scale up c and d.
    
    755
    +      (when (<= cd (* +cdiv-rmin+ +cdiv-2/eps+))
    
    756
    +	(setf y (* y +cdiv-be+)
    
    757
    +	      s (* s +cdiv-be+)))
    
    758
    +      (* s
    
    759
    +	 (robust-internal x y)))))
    
    760
    +
    
    761
    +;; Smith's algorithm for complex division for (complex single-float).
    
    762
    +;; We convert the parts to double-floats before computing the result.
    
    763
    +(defun cdiv-single-float (x y)
    
    764
    +  "Accurate division of complex single-float numbers x and y."
    
    765
    +  (declare (type (complex single-float) x y))
    
    766
    +  (let ((a (float (realpart x) 1d0))
    
    767
    +	(b (float (imagpart x) 1d0))
    
    768
    +	(c (float (realpart y) 1d0))
    
    769
    +	(d (float (imagpart y) 1d0)))
    
    770
    +    (cond ((< (abs c) (abs d))
    
    771
    +	   (let* ((r (/ c d))
    
    772
    +		  (denom (+ (* c r) d))
    
    773
    +		  (e (float (/ (+ (* a r) b) denom) 1f0))
    
    774
    +		  (f (float (/ (- (* b r) a) denom) 1f0)))
    
    775
    +	     (complex e f)))
    
    776
    +	  (t
    
    777
    +	   (let* ((r (/ d c))
    
    778
    +		  (denom (+ c (* d r)))
    
    779
    +		  (e (float (/ (+ a (* b r)) denom) 1f0))
    
    780
    +		  (f (float (/ (- b (* a r)) denom) 1f0)))
    
    781
    +	     (complex e f))))))
    
    782
    +
    
    783
    +;; Generic implementation of Smith's algorithm.
    
    784
    +(defun cdiv-generic (x y)
    
    785
    +  "Complex division of generic numbers x and y.  One of x or y should be
    
    786
    +  a complex."
    
    787
    +  (let ((a (realpart x))
    
    788
    +	(b (imagpart x))
    
    789
    +	(c (realpart y))
    
    790
    +	(d (imagpart y)))
    
    791
    +    (cond ((< (abs c) (abs d))
    
    792
    +	   (let* ((r (/ c d))
    
    793
    +		  (denom (+ (* c r) d))
    
    794
    +		  (e (/ (+ (* a r) b) denom))
    
    795
    +		  (f (/ (- (* b r) a) denom)))
    
    796
    +	     (canonical-complex e f)))
    
    797
    +	  (t
    
    798
    +	   (let* ((r (/ d c))
    
    799
    +		  (denom (+ c (* d r)))
    
    800
    +		  (e (/ (+ a (* b r)) denom))
    
    801
    +		  (f (/ (- b (* a r)) denom)))
    
    802
    +	     (canonical-complex e f))))))
    
    596 803
     
    
    597 804
     (defun two-arg-/ (x y)
    
    598 805
       (number-dispatch ((x number) (y number))
    
    599 806
         (float-contagion / x y (ratio integer))
    
    600
    -     
    
    601
    -    ((complex complex)
    
    602
    -     (let* ((rx (realpart x))
    
    603
    -	    (ix (imagpart x))
    
    604
    -	    (ry (realpart y))
    
    605
    -	    (iy (imagpart y)))
    
    606
    -       (if (> (abs ry) (abs iy))
    
    607
    -	   (let* ((r (/ iy ry))
    
    608
    -		  (dn (+ ry (* r iy))))
    
    609
    -	     (canonical-complex (/ (+ rx (* ix r)) dn)
    
    610
    -				(/ (- ix (* rx r)) dn)))
    
    611
    -	   (let* ((r (/ ry iy))
    
    612
    -		  (dn (+ iy (* r ry))))
    
    613
    -	     (canonical-complex (/ (+ (* rx r) ix) dn)
    
    614
    -				(/ (- (* ix r) rx) dn))))))
    
    615
    -    (((foreach integer ratio single-float double-float) complex)
    
    807
    +
    
    808
    +    (((complex single-float)
    
    809
    +      (foreach (complex rational) (complex single-float)))
    
    810
    +     (cdiv-single-float x (coerce y '(complex single-float))))
    
    811
    +    (((complex double-float)
    
    812
    +      (foreach (complex rational) (complex single-float) (complex double-float)))
    
    813
    +     (cdiv-double-float x (coerce y '(complex double-float))))
    
    814
    +
    
    815
    +    (((foreach integer ratio single-float (complex rational))
    
    816
    +      (complex single-float))
    
    817
    +     (cdiv-single-float (coerce x '(complex single-float))
    
    818
    +			y))
    
    819
    +    
    
    820
    +    (((foreach integer ratio single-float double-float (complex rational)
    
    821
    +	       (complex single-float))
    
    822
    +      (complex double-float))
    
    823
    +     (cdiv-double-float (coerce x '(complex double-float))
    
    824
    +			y))
    
    825
    +    (((complex double-double-float)
    
    826
    +      (foreach (complex rational) (complex single-float) (complex double-float)
    
    827
    +	       (complex double-double-float)))
    
    828
    +     ;; We should do something better for double-double floats.
    
    829
    +     (cdiv-generic x y))
    
    830
    +    
    
    831
    +    (((foreach integer ratio single-float double-float double-double-float
    
    832
    +	       (complex rational) (complex single-float) (complex double-float))
    
    833
    +      (complex double-double-float))
    
    834
    +     (cdiv-generic x y))
    
    835
    +
    
    836
    +    (((foreach integer ratio single-float double-float double-double-float)
    
    837
    +      (complex rational))
    
    838
    +     ;; Smith's algorithm, but takes advantage of the fact that the
    
    839
    +     ;; numerator is a real number and not complex.
    
    616 840
          (let* ((ry (realpart y))
    
    617 841
     	    (iy (imagpart y)))
    
    618 842
            (if (> (abs ry) (abs iy))
    
    ... ... @@ -624,10 +848,23 @@
    624 848
     		  (dn (* iy (+ 1 (* r r)))))
    
    625 849
     	     (canonical-complex (/ (* x r) dn)
    
    626 850
     				(/ (- x) dn))))))
    
    627
    -    ((complex (or rational float))
    
    851
    +    (((complex rational)
    
    852
    +      (complex rational))
    
    853
    +     ;; We probably don't need to do Smith's algorithm for rationals.
    
    854
    +     ;; A naive implementation of coplex division has no issues.
    
    855
    +     (cdiv-generic x y))
    
    856
    +
    
    857
    +    (((foreach (complex rational) (complex single-float) (complex double-float)
    
    858
    +	       (complex double-double-float))
    
    859
    +      (or rational float))
    
    628 860
          (canonical-complex (/ (realpart x) y)
    
    629 861
     			(/ (imagpart x) y)))
    
    630
    -    
    
    862
    +      
    
    863
    +    ((double-float
    
    864
    +      (complex single-float))
    
    865
    +     (cdiv-double-float (coerce x '(complex double-float))
    
    866
    +			(coerce y '(complex double-float))))
    
    867
    +
    
    631 868
         ((ratio ratio)
    
    632 869
          (let* ((nx (numerator x))
    
    633 870
     	    (dx (denominator x))
    
    ... ... @@ -656,6 +893,7 @@
    656 893
            (build-ratio (maybe-truncate nx gcd)
    
    657 894
     		    (* (maybe-truncate y gcd) (denominator x)))))))
    
    658 895
     
    
    896
    +(declaim (ext:end-block))
    
    659 897
     
    
    660 898
     (defun %negate (n)
    
    661 899
       (number-dispatch ((n number))
    

  • src/compiler/float-tran.lisp
    ... ... @@ -1804,46 +1804,13 @@
    1804 1804
       #+double-double
    
    1805 1805
       (frob double-double-float))
    
    1806 1806
       
    
    1807
    -#+(and sse2 complex-fp-vops)
    
    1808 1807
     (macrolet
    
    1809
    -    ((frob (type one)
    
    1810
    -       `(deftransform / ((x y) (,type ,type) *
    
    1811
    -			 :policy (> speed space))
    
    1812
    -	  ;; Divide a complex by a complex
    
    1808
    +    ((frob (type name)
    
    1809
    +       `(deftransform / ((x y) ((complex ,type) (complex ,type)) *)
    
    1810
    +		      (,name x y))))
    
    1811
    +  (frob double-float kernel::cdiv-double-float)
    
    1812
    +  (frob single-float kernel::cdiv-single-float))
    
    1813 1813
     
    
    1814
    -	  ;; Here's how we do a complex division
    
    1815
    -	  ;;
    
    1816
    -	  ;; Compute (xr + i*xi)/(yr + i*yi)
    
    1817
    -	  ;;
    
    1818
    -	  ;; Assume |yi| < |yr|.  Then
    
    1819
    -	  ;;
    
    1820
    -	  ;; (xr + i*xi)      (xr + i*xi)
    
    1821
    -	  ;; ----------- = -----------------
    
    1822
    -	  ;; (yr + i*yi)   yr*(1 + i*(yi/yr))
    
    1823
    -	  ;;
    
    1824
    -	  ;;               (xr + i*xi)*(1 - i*(yi/yr))
    
    1825
    -	  ;;             = ---------------------------
    
    1826
    -	  ;;                   yr*(1 + (yi/yr)^2)
    
    1827
    -	  ;;
    
    1828
    -	  ;;               (xr + i*xi)*(1 - i*(yi/yr))
    
    1829
    -	  ;;             = ---------------------------
    
    1830
    -	  ;;                   yr + (yi/yr)*yi
    
    1831
    -	  ;;
    
    1832
    -	  ;; This allows us to use a fast complex multiply followed by
    
    1833
    -	  ;; a real division.
    
    1834
    -	  '(let* ((ry (realpart y))
    
    1835
    -		  (iy (imagpart y)))
    
    1836
    -	    (if (> (abs ry) (abs iy))
    
    1837
    -		(let* ((r (/ iy ry))
    
    1838
    -		       (dn (+ ry (* r iy))))
    
    1839
    -		  (/ (* x (complex ,one r))
    
    1840
    -		     dn))
    
    1841
    -		(let* ((r (/ ry iy))
    
    1842
    -		       (dn (+ iy (* r ry))))
    
    1843
    -		  (/ (* x (complex r ,(- one)))
    
    1844
    -		     dn)))))))
    
    1845
    -  (frob (complex single-float) 1f0)
    
    1846
    -  (frob (complex double-float) 1d0))
    
    1847 1814
     
    
    1848 1815
     ;;;; Complex contagion:
    
    1849 1816
     
    

  • src/general-info/release-22a.md
    ... ... @@ -34,6 +34,9 @@ public domain.
    34 34
         * #446: Use C compiler to get errno values to update UNIX
    
    35 35
                 defpackage with errno symbols
    
    36 36
         * #453: Use correct flags for analyzer and always save logs.
    
    37
    +    * #456: Improve accuracy for division of complex double-floats
    
    38
    +            using Baudin and Smith's robust complex division algorithm
    
    39
    +            with improvements by Patrick McGehearty.
    
    37 40
         * #458: Spurious overflow in double-double-float multiply
    
    38 41
       * Other changes:
    
    39 42
       * Improvements to the PCL implementation of CLOS:
    

  • tests/float.lisp
    ... ... @@ -348,3 +348,211 @@
    348 348
       (:tag :issues)
    
    349 349
       (assert-equal -2w300
    
    350 350
     		(* -2w300 1w0)))
    
    351
    +
    
    352
    +
    
    353
    +
    
    354
    +;; Rudimentary code to read C %a formatted numbers that look like
    
    355
    +;; "-0x1.c4dba4ba1ee79p-620".  We assume STRING is exactly in this
    
    356
    +;; format.  No error-checking is done.
    
    357
    +(defun parse-hex-float (string)
    
    358
    +  (let* ((sign (if (char= (aref string 0) #\-)
    
    359
    +		   -1
    
    360
    +		   1))
    
    361
    +	 (dot-posn (position #\. string))
    
    362
    +	 (p-posn (position #\p string))
    
    363
    +	 (lead (parse-integer string :start (1- dot-posn) :end dot-posn))
    
    364
    +	 (frac (parse-integer string :start (1+ dot-posn) :end p-posn :radix 16))
    
    365
    +	 (exp (parse-integer string :start (1+ p-posn))))
    
    366
    +    (* sign
    
    367
    +       (scale-float (float (+ (ash lead 52)
    
    368
    +			      frac)
    
    369
    +			   1d0)
    
    370
    +		    (- exp 52)))))
    
    371
    +
    
    372
    +;; Relative error in terms of bits of accuracy.  This is the
    
    373
    +;; definition used by Baudin and Smith.  A result of 53 means the two
    
    374
    +;; numbers have identical bits.  For complex numbers, we use the min
    
    375
    +;; of the bits of accuracy of the real and imaginary parts.
    
    376
    +(defun rel-err (computed expected)
    
    377
    +  (flet ((rerr (c e)
    
    378
    +	   (let ((diff (abs (- c e))))
    
    379
    +	     (if (zerop diff)
    
    380
    +		 (float-digits diff)
    
    381
    +		 (floor (- (log (/ diff (abs e)) 2d0)))))))
    
    382
    +    (min (rerr (realpart computed) (realpart expected))
    
    383
    +	 (rerr (imagpart computed) (imagpart expected)))))
    
    384
    +
    
    385
    +(defun do-cdiv-test (x y z-true expected-rel)
    
    386
    +  (let* ((z (/ x y))
    
    387
    +	 (rel (rel-err z z-true)))
    
    388
    +    (assert-equal expected-rel
    
    389
    +		  rel
    
    390
    +		  x y z z-true rel)))
    
    391
    +;; Issue #456: improve accuracy of division of complex double-floats.
    
    392
    +;;
    
    393
    +;; Tests for complex division.  Tests 1-10 are from Baudin and Smith.
    
    394
    +;; Test 11 is an example from Maxima.  Test 12 is an example from the
    
    395
    +;; ansi-tests where (/ z z) didn't produce exactly 1.  Tests 13-16 are
    
    396
    +;; for examples for improvement iterations 1-4 from McGehearty.
    
    397
    +(macrolet
    
    398
    +    ((frob (name x y z-true rel)
    
    399
    +       `(define-test ,name
    
    400
    +	  (:tag :issues)
    
    401
    +	  (do-cdiv-test ,x ,y ,z-true ,rel))))
    
    402
    +  ;; First cases are from Baudin and Smith
    
    403
    +  ;; 1
    
    404
    +  (frob cdiv.baudin-case.1
    
    405
    +	(complex 1d0 1d0)
    
    406
    +	(complex 1d0 (scale-float 1d0 1023))
    
    407
    +	(complex (scale-float 1d0 -1023)
    
    408
    +		 (scale-float -1d0 -1023))
    
    409
    +	53)
    
    410
    +  ;; 2
    
    411
    +  (frob cdiv.baudin-case.2
    
    412
    +	(complex 1d0 1d0)
    
    413
    +	(complex (scale-float 1d0 -1023) (scale-float 1d0 -1023))
    
    414
    +	(complex (scale-float 1d0 1023) 0)
    
    415
    +	53)
    
    416
    +  ;; 3
    
    417
    +  (frob cdiv.baudin-case.3
    
    418
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 -1023))
    
    419
    +	(complex (scale-float 1d0 677) (scale-float 1d0 -677))
    
    420
    +	(complex (scale-float 1d0 346) (scale-float -1d0 -1008))
    
    421
    +	53)
    
    422
    +  ;; 4
    
    423
    +  (frob cdiv.baudin-case.4.overflow
    
    424
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    425
    +	(complex 1d0 1d0)
    
    426
    +	(complex (scale-float 1d0 1023) 0)
    
    427
    +	53)
    
    428
    +  ;; 5
    
    429
    +  (frob cdiv.baudin-case.5.underflow-ratio
    
    430
    +	(complex (scale-float 1d0 1020) (scale-float 1d0 -844))
    
    431
    +	(complex (scale-float 1d0 656) (scale-float 1d0 -780))
    
    432
    +	(complex (scale-float 1d0 364) (scale-float -1d0 -1072))
    
    433
    +	53)
    
    434
    +  ;; 6
    
    435
    +  (frob cdiv.baudin-case.6.underflow-realpart
    
    436
    +	(complex (scale-float 1d0 -71) (scale-float 1d0 1021))
    
    437
    +	(complex (scale-float 1d0 1001) (scale-float 1d0 -323))
    
    438
    +	(complex (scale-float 1d0 -1072) (scale-float 1d0 20))
    
    439
    +	53)
    
    440
    +  ;; 7
    
    441
    +  (frob cdiv.baudin-case.7.overflow-both-parts
    
    442
    +	(complex (scale-float 1d0 -347) (scale-float 1d0 -54))
    
    443
    +	(complex (scale-float 1d0 -1037) (scale-float 1d0 -1058))
    
    444
    +	(complex 3.898125604559113300d289 8.174961907852353577d295)
    
    445
    +	53)
    
    446
    +  ;; 8
    
    447
    +  (frob cdiv.baudin-case.8
    
    448
    +	(complex (scale-float 1d0 -1074) (scale-float 1d0 -1074))
    
    449
    +	(complex (scale-float 1d0 -1073) (scale-float 1d0 -1074))
    
    450
    +	(complex 0.6d0 0.2d0)
    
    451
    +	53)
    
    452
    +  ;; 9
    
    453
    +  (frob cdiv.baudin-case.9
    
    454
    +	(complex (scale-float 1d0 1015) (scale-float 1d0 -989))
    
    455
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    456
    +	(complex 0.001953125d0 -0.001953125d0)
    
    457
    +	53)
    
    458
    +  ;; 10
    
    459
    +  (frob cdiv.baudin-case.10.improve-imagpart-accuracy
    
    460
    +	(complex (scale-float 1d0 -622) (scale-float 1d0 -1071))
    
    461
    +	(complex (scale-float 1d0 -343) (scale-float 1d0 -798))
    
    462
    +	(complex 1.02951151789360578d-84 6.97145987515076231d-220)
    
    463
    +	53)
    
    464
    +  ;; 11
    
    465
    +  ;;
    
    466
    +  ;; From Maxima.  This was from a (private) email where Maxima used
    
    467
    +  ;; CL:/ to compute the ratio but was not very accurate.
    
    468
    +  (frob cdiv.maxima-case
    
    469
    +	#c(5.43d-10 1.13d-100)
    
    470
    +	#c(1.2d-311 5.7d-312)
    
    471
    +	#c(3.691993880674614517999740937026568563794896024143749539711267954d301
    
    472
    +	   -1.753697093319947872394996242210428954266103103602859195409591583d301)
    
    473
    +	52)
    
    474
    +  ;; 12
    
    475
    +  ;;
    
    476
    +  ;; Found by ansi tests. z/z should be exactly 1.
    
    477
    +  (frob cdiv.ansi-test-z/z
    
    478
    +	#c(1.565640716292489d19 0.0d0)
    
    479
    +	#c(1.565640716292489d19 0.0d0)
    
    480
    +	#c(1d0 0)
    
    481
    +	53)
    
    482
    +  ;; 13
    
    483
    +  ;; Iteration 1.  Without this, we would instead return
    
    484
    +  ;;
    
    485
    +  ;;   (complex (parse-hex-float "0x1.ba8df8075bceep+155")
    
    486
    +  ;;            (parse-hex-float "-0x1.a4ad6329485f0p-895"))
    
    487
    +  ;;
    
    488
    +  ;; whose imaginary part is quite a bit off.
    
    489
    +  (frob cdiv.mcgehearty-iteration.1
    
    490
    +	(complex (parse-hex-float "0x1.73a3dac1d2f1fp+509")
    
    491
    +		 (parse-hex-float "-0x1.c4dba4ba1ee79p-620"))
    
    492
    +	(complex (parse-hex-float "0x1.adf526c249cf0p+353")
    
    493
    +		 (parse-hex-float "0x1.98b3fbc1677bbp-697"))
    
    494
    +	(complex (parse-hex-float "0x1.BA8DF8075BCEEp+155")
    
    495
    +		 (parse-hex-float "-0x1.A4AD628DA5B74p-895"))
    
    496
    +	53)
    
    497
    +  ;; 14
    
    498
    +  ;; Iteration 2.
    
    499
    +  (frob cdiv.mcgehearty-iteration.2
    
    500
    +	(complex (parse-hex-float "-0x0.000000008e4f8p-1022")
    
    501
    +		 (parse-hex-float "0x0.0000060366ba7p-1022"))
    
    502
    +	(complex (parse-hex-float "-0x1.605b467369526p-245")
    
    503
    +		 (parse-hex-float "0x1.417bd33105808p-256"))
    
    504
    +	(complex (parse-hex-float "0x1.cde593daa4ffep-810")
    
    505
    +		 (parse-hex-float "-0x1.179b9a63df6d3p-799"))
    
    506
    +	52)
    
    507
    +  ;; 15
    
    508
    +  ;; Iteration 3
    
    509
    +  (frob cdiv.mcgehearty-iteration.3
    
    510
    +	(complex (parse-hex-float "0x1.cb27eece7c585p-355 ")
    
    511
    +		 (parse-hex-float "0x0.000000223b8a8p-1022"))
    
    512
    +	(complex (parse-hex-float "-0x1.74e7ed2b9189fp-22")
    
    513
    +		 (parse-hex-float "0x1.3d80439e9a119p-731"))
    
    514
    +	(complex (parse-hex-float "-0x1.3b35ed806ae5ap-333")
    
    515
    +		 (parse-hex-float "-0x0.05e01bcbfd9f6p-1022"))
    
    516
    +	53)
    
    517
    +  ;; 16
    
    518
    +  ;; Iteration 4
    
    519
    +  (frob cdiv.mcgehearty-iteration.4
    
    520
    +	(complex (parse-hex-float "-0x1.f5c75c69829f0p-530")
    
    521
    +		 (parse-hex-float "-0x1.e73b1fde6b909p+316"))
    
    522
    +	(complex (parse-hex-float "-0x1.ff96c3957742bp+1023")
    
    523
    +		 (parse-hex-float "0x1.5bd78c9335899p+1021"))
    
    524
    +	(complex (parse-hex-float "-0x1.423c6ce00c73bp-710")
    
    525
    +		 (parse-hex-float "0x1.d9edcf45bcb0ep-708"))
    
    526
    +	52))
    
    527
    +
    
    528
    +(define-test complex-division.misc
    
    529
    +    (:tag :issue)
    
    530
    +  (let ((num '(1
    
    531
    +	       1/2
    
    532
    +	       1.0
    
    533
    +	       1d0
    
    534
    +	       #c(1 2)
    
    535
    +	       #c(1.0 2.0)
    
    536
    +	       #c(1d0 2d0)
    
    537
    +	       #c(1w0 2w0))))
    
    538
    +    ;; Try all combinations of divisions of different types.  This is
    
    539
    +    ;; primarily to test that we got all the numeric contagion cases
    
    540
    +    ;; for division in CL:/.
    
    541
    +    (dolist (x num)
    
    542
    +      (dolist (y num)
    
    543
    +	(assert-true (/ x y)
    
    544
    +		     x y)))))
    
    545
    +
    
    546
    +(define-test complex-division.single
    
    547
    +    (:tag :issues)
    
    548
    +  (let* ((x #c(1 2))
    
    549
    +	 (y (complex (expt 2 127) (expt 2 127)))
    
    550
    +	 (expected (coerce (/ x y)
    
    551
    +			   '(complex single-float))))
    
    552
    +    ;; A naive implementation of complex division would cause an
    
    553
    +    ;; overflow in computing the denominator.
    
    554
    +    (assert-equal expected
    
    555
    +		  (/ (coerce x '(complex single-float))
    
    556
    +		     (coerce y '(complex single-float)))
    
    557
    +		  x
    
    558
    +		  y)))