Raymond Toy pushed to branch issue-461-cdiv-use-4-doubles at cmucl / cmucl

Commits:

2 changed files:

Changes:

  • src/code/numbers.lisp
    ... ... @@ -602,53 +602,11 @@
    602 602
     ;; In particular iteration 1 and 3 are added.  Iteration 2 and 4 were
    
    603 603
     ;; not added.  The test examples from iteration 2 and 4 didn't change
    
    604 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
    -;; 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
    -;; 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 (for SCALE-FLOAT) of the corresponding DOUBLE-FLOAT values
    
    620
    -;; above.
    
    621 605
     ;;
    
    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.
    
    628
    -(defconstant +cdiv-dd-rmin+
    
    629
    -  least-positive-normalized-double-float)
    
    630
    -(defconstant +cdiv-dd-rbig+
    
    631
    -  (/ most-positive-double-float 2))
    
    632
    -(defconstant +cdiv-dd-rmin2+
    
    633
    -  (scale-float 1d0 -106))
    
    634
    -(defconstant +cdiv-dd-rminscal+
    
    635
    -  (scale-float 1d0 102))
    
    636
    -(defconstant +cdiv-dd-rmax2+
    
    637
    -  (* +cdiv-dd-rbig+ +cdiv-dd-rmin2+))
    
    638
    -;; Epsilon for double-doubles isn't really well-defined because things
    
    639
    -;; like (+ 1w0 1w-200) is a valid double-double float.
    
    640
    -(defconstant +cdiv-dd-eps+
    
    641
    -  (scale-float 1d0 -104))
    
    642
    -(defconstant +cdiv-dd-be+
    
    643
    -  (/ 2 (* +cdiv-dd-eps+ +cdiv-dd-eps+)))
    
    644
    -(defconstant +cdiv-dd-2/eps+
    
    645
    -  (/ 2 +cdiv-dd-eps+))
    
    646
    -
    
    647
    -
    
    648
    -;; Make these functions accessible.  cdiv-double-float and
    
    649
    -;; cdiv-single-float are used by deftransforms.  Of course, two-arg-/
    
    650
    -;; is the interface to division.  cdiv-generic isn't used anywhere
    
    651
    -;; else.
    
    606
    +;; Make these functions accessible outside the block compilation.
    
    607
    +;; CDIV-DOUBLE-FLOAT and CDIV-SINGLE-FLOAT are used by deftransforms.
    
    608
    +;; Of course, TWO-ARG-/ is the interface to division.  CDIV-GENERIC
    
    609
    +;; isn't used anywhere else.
    
    652 610
     (declaim (ext:start-block cdiv-double-float cdiv-single-float
    
    653 611
     			  cdiv-double-double-float
    
    654 612
     			  two-arg-/))
    
    ... ... @@ -657,27 +615,15 @@
    657 615
     ;; implementation is basically identical except for the constants.
    
    658 616
     ;; use a macro to generate both versions.
    
    659 617
     (eval-when (:compile-toplevel)
    
    660
    -(defmacro define-cdiv (type)
    
    661
    -  (let* ((dd (if (eq type 'double-float)
    
    662
    -		 ""
    
    663
    -		 "DD-"))
    
    664
    -	 (opt '((optimize (speed 3) (safety 0))))
    
    618
    +(defmacro define-cdiv (type &key rmin rbig rmin2 rminscal eps)
    
    619
    +  (let* ((opt '((optimize (speed 3) (safety 0))))
    
    665 620
     	 (name (symbolicate "CDIV-" type))
    
    666 621
     	 (compreal (symbolicate "CDIV-" type "-INTERNAL-COMPREAL"))
    
    667 622
     	 (subinternal (symbolicate "CDIV-" type "-ROBUST-SUBINTERNAL"))
    
    668 623
     	 (internal (symbolicate "CDIV-" type "-ROBUST-INTERNAL"))
    
    669 624
     	 (docstring (let ((*print-case* :downcase))
    
    670 625
     		      (format nil "Accurate division of complex ~A numbers x and y."
    
    671
    -			      type)))
    
    672
    -	 ;; Create the correct symbols for the constants we need,
    
    673
    -	 ;; as defined above.
    
    674
    -	 (+rmin+ (symbolicate "+CDIV-" dd "RMIN+"))
    
    675
    -	 (+rbig+ (symbolicate "+CDIV-" dd "RBIG+"))
    
    676
    -	 (+rmin2+ (symbolicate "+CDIV-" dd "RMIN2+"))
    
    677
    -	 (+rminscal+ (symbolicate "+CDIV-" dd "RMINSCAL+"))
    
    678
    -	 (+rmax2+ (symbolicate "+CDIV-" dd "RMAX2+"))
    
    679
    -	 (+be+ (symbolicate "+CDIV-" dd "BE+"))
    
    680
    -	 (+2/eps+ (symbolicate "+CDIV-" dd "2/EPS+")))
    
    626
    +			      type))))
    
    681 627
         `(progn
    
    682 628
            (defun ,compreal (a b c d r tt)
    
    683 629
     	 (declare (,type a b c d r tt)
    
    ... ... @@ -699,7 +645,7 @@
    699 645
     	 ;;                       = (a + b*r)/(c + d*r).
    
    700 646
     	 ;;
    
    701 647
     	 ;; Thus tt = (c + d*r).
    
    702
    -	 (cond ((>= (abs r) ,+rmin+)
    
    648
    +	 (cond ((>= (abs r) ,rmin)
    
    703 649
     		(let ((br (* b r)))
    
    704 650
     		  (if (/= br 0)
    
    705 651
     		      (/ (+ a br) tt)
    
    ... ... @@ -719,46 +665,51 @@
    719 665
     		  ,@opt)
    
    720 666
     	 (let* ((r (/ d c))
    
    721 667
     		(tt (+ c (* d r))))
    
    722
    -	   ;; e is the real part and f is the imaginary part.  We
    
    723
    -	   ;; can use internal-compreal for the imaginary part by
    
    724
    -	   ;; noticing that the imaginary part of (a+i*b)/(c+i*d) is
    
    725
    -	   ;; the same as the real part of (b-i*a)/(c+i*d).
    
    668
    +	   ;; e is the real part and f is the imaginary part.  We can
    
    669
    +	   ;; use COMPREAL for the imaginary part by noticing that the
    
    670
    +	   ;; imaginary part of (a+i*b)/(c+i*d) is the same as the
    
    671
    +	   ;; real part of (b-i*a)/(c+i*d).
    
    726 672
     	   (let ((e (,compreal a b c d r tt))
    
    727 673
     		 (f (,compreal b (- a) c d r tt)))
    
    728 674
     	     (values e f))))
    
    729 675
            (defun ,internal (a b c d)
    
    730
    -	 (declare (,type a b c d)
    
    731
    -		  ,@opt)
    
    676
    +	   (declare (,type a b c d)
    
    677
    +		    ,@opt)
    
    732 678
     	 (flet ((maybe-scale (abs-tst a b c d)
    
    733 679
     		  (declare (,type a b c d))
    
    734 680
     		  ;; This implements McGehearty's iteration 3 to
    
    735 681
     		  ;; handle the case when some values are too big
    
    736 682
     		  ;; and should be scaled down.  Also if some
    
    737 683
     		  ;; values are too tiny, scale them up.
    
    738
    -		  (let ((abs-a (abs a))
    
    684
    +		  (let ((+rbig+ ,rbig)
    
    685
    +			(+rmin2+ ,rmin2)
    
    686
    +			(+rminscal+ ,rminscal)
    
    687
    +			(+rmax2+ (* ,rbig ,rmin2))
    
    688
    +			(+rmin+ ,rmin)
    
    689
    +			(abs-a (abs a))
    
    739 690
     			(abs-b (abs b)))
    
    740
    -		    (if (or (> abs-tst ,+rbig+)
    
    741
    -			    (> abs-a ,+rbig+)
    
    742
    -			    (> abs-b ,+rbig+))
    
    691
    +		    (if (or (> abs-tst +rbig+)
    
    692
    +			    (> abs-a +rbig+)
    
    693
    +			    (> abs-b +rbig+))
    
    743 694
     			(setf a (* a 0.5d0)
    
    744 695
     			      b (* b 0.5d0)
    
    745 696
     			      c (* c 0.5d0)
    
    746 697
     			      d (* d 0.5d0))
    
    747
    -			(if (< abs-tst ,+rmin2+)
    
    748
    -			    (setf a (* a ,+rminscal+)
    
    749
    -				  b (* b ,+rminscal+)
    
    750
    -				  c (* c ,+rminscal+)
    
    751
    -				  d (* d ,+rminscal+))
    
    752
    -			    (if (or (and (< abs-a ,+rmin+)
    
    753
    -					 (< abs-b ,+rmax2+)
    
    754
    -					 (< abs-tst ,+rmax2+))
    
    755
    -				    (and (< abs-b ,+rmin+)
    
    756
    -					 (< abs-a ,+rmax2+)
    
    757
    -					 (< abs-tst ,+rmax2+)))
    
    758
    -				(setf a (* a ,+rminscal+)
    
    759
    -				      b (* b ,+rminscal+)
    
    760
    -				      c (* c ,+rminscal+)
    
    761
    -				      d (* d ,+rminscal+)))))
    
    698
    +			(if (< abs-tst +rmin2+)
    
    699
    +			    (setf a (* a +rminscal+)
    
    700
    +				  b (* b +rminscal+)
    
    701
    +				  c (* c +rminscal+)
    
    702
    +				  d (* d +rminscal+))
    
    703
    +			    (if (or (and (< abs-a +rmin+)
    
    704
    +					 (< abs-b +rmax2+)
    
    705
    +					 (< abs-tst +rmax2+))
    
    706
    +				    (and (< abs-b +rmin+)
    
    707
    +					 (< abs-a +rmax2+)
    
    708
    +					 (< abs-tst +rmax2+)))
    
    709
    +				(setf a (* a +rminscal+)
    
    710
    +				      b (* b +rminscal+)
    
    711
    +				      c (* c +rminscal+)
    
    712
    +				      d (* d +rminscal+)))))
    
    762 713
     		    (values a b c d))))
    
    763 714
     	   (cond
    
    764 715
     	     ((<= (abs d) (abs c))
    
    ... ... @@ -781,48 +732,82 @@
    781 732
     		(multiple-value-bind (e f)
    
    782 733
     		    (,subinternal b a d c)
    
    783 734
     		  (values e (- f))))))))
    
    784
    -       (defun ,name (a b c d)
    
    785
    -	 ,docstring
    
    786
    -	 (declare (,type a b c d)
    
    787
    -		  ,@opt)
    
    788
    -	 (let* ((ab (max (abs a) (abs b)))
    
    789
    -		(cd (max (abs c) (abs d)))
    
    790
    -		;; S is always multipled by a power of 2.  It's either
    
    791
    -		;; 2, 0.5, or +be+, which is also a power of two.
    
    792
    -		;; (Either 2^105 or 2^209).  Hence, we can just use a
    
    793
    -		;; double-float instead of a double-double-float
    
    794
    -		;; because the double-double always has 0d0 for the lo
    
    795
    -		;; part.
    
    796
    -		(s 1d0))
    
    797
    -	   (declare (double-float s))
    
    798
    -	   ;; If a or b is big, scale down a and b.
    
    799
    -	   (when (>= ab ,+rbig+)
    
    800
    -	     (setf a (* a 0.5d0)
    
    801
    -		   b (* b 0.5d0)
    
    802
    -		   s (* s 2)))
    
    803
    -	   ;; If c or d is big, scale down c and d.
    
    804
    -	   (when (>= cd ,+rbig+)
    
    805
    -	     (setf c (* c 0.5d0)
    
    806
    -		   d (* d 0.5d0)
    
    807
    -		   s (* s 0.5d0)))
    
    808
    -	   ;; If a or b is tiny, scale up a and b.
    
    809
    -	   (when (<= ab (* ,+rmin+ ,+2/eps+))
    
    810
    -	     (setf a (* a ,+be+)
    
    811
    -		   b (* b ,+be+)
    
    812
    -		   s (/ s ,+be+)))
    
    813
    -	   ;; If c or d is tiny, scale up c and d.
    
    814
    -	   (when (<= cd (* ,+rmin+ ,+2/eps+))
    
    815
    -	     (setf c (* c ,+be+)
    
    816
    -		   d (* d ,+be+)
    
    817
    -		   s (* s ,+be+)))
    
    818
    -	   (multiple-value-bind (e f)
    
    819
    -	       (,internal a b c d)
    
    820
    -	     (complex (* s e)
    
    821
    -		      (* s f))))))))
    
    735
    +	 (defun ,name (xr xi yr yi)
    
    736
    +	   ,docstring
    
    737
    +	   (declare (,type xr xi yr yi)
    
    738
    +		    ,@opt)
    
    739
    +	   (let ((+rmin+ ,rmin)
    
    740
    +		 (+rbig+ ,rbig)
    
    741
    +		 (+2/eps+ (/ 2 ,eps))
    
    742
    +		 (+be+ (/ 2 (* ,eps ,eps))))
    
    743
    +	     (let* ((max-x (max (abs xr) (abs xi)))
    
    744
    +		    (max-y (max (abs yr) (abs yi)))
    
    745
    +		    ;; S is always multipled by xr power of 2.  It's
    
    746
    +		    ;; multiplied by either 2, 0.5, or +be+, which is
    
    747
    +		    ;; also xr power of two.  (Either 2^105 or 2^209).
    
    748
    +		    ;; Hence, we can just use xr double-float instead
    
    749
    +		    ;; of xr double-double-float because the
    
    750
    +		    ;; double-double always has 0d0 for the lo part.
    
    751
    +		    (s 1d0))
    
    752
    +	       (declare (double-float s))
    
    753
    +	       ;; If xr or xi is big, scale down xr and xi.
    
    754
    +	       (when (>= max-x +rbig+)
    
    755
    +		 (setf xr (* xr 0.5d0)
    
    756
    +		       xi (* xi 0.5d0)
    
    757
    +		       s (* s 2)))
    
    758
    +	       ;; If yr or yi is big, scale down yr and yi.
    
    759
    +	       (when (>= max-y +rbig+)
    
    760
    +		 (setf yr (* yr 0.5d0)
    
    761
    +		       yi (* yi 0.5d0)
    
    762
    +		       s (* s 0.5d0)))
    
    763
    +	       ;; If xr or xi is tiny, scale up xr and xi.
    
    764
    +	       (when (<= max-x (* +rmin+ +2/eps+))
    
    765
    +		 (setf xr (* xr +be+)
    
    766
    +		       xi (* xi +be+)
    
    767
    +		       s (/ s +be+)))
    
    768
    +	       ;; If yr or yi is tiny, scale up yr and yi.
    
    769
    +	       (when (<= max-y (* +rmin+ +2/eps+))
    
    770
    +		 (setf yr (* yr +be+)
    
    771
    +		       yi (* yi +be+)
    
    772
    +		       s (* s +be+)))
    
    773
    +	       (multiple-value-bind (e f)
    
    774
    +		   (,internal xr xi yr yi)
    
    775
    +		 (complex (* s e)
    
    776
    +			  (* s f)))))))))
    
    822 777
     )
    
    823 778
     
    
    824
    -(define-cdiv double-float)
    
    825
    -(define-cdiv double-double-float)
    
    779
    +(define-cdiv double-float
    
    780
    +  :rmin least-positive-normalized-double-float
    
    781
    +  :rbig (/ most-positive-double-float 2)
    
    782
    +  :rmin2 (scale-float 1d0 -53)
    
    783
    +  :rminscal (scale-float 1d0 51)
    
    784
    +  ;; This is the value of %eps from Scilab
    
    785
    +  :eps (scale-float 1d0 -52))
    
    786
    +
    
    787
    +;; Same constants but for DOUBLE-DOUBLE-FLOATS.  Some of these aren't
    
    788
    +;; well-defined for DOUBLE-DOUBLE-FLOATS (like eps) so we make our
    
    789
    +;; best guess at what they might be.  Since double-doubles have
    
    790
    +;; twice as many bits of precision as a DOUBLE-FLOAT, we generally
    
    791
    +;; just double the exponent (for SCALE-FLOAT) of the corresponding
    
    792
    +;; DOUBLE-FLOAT values above.
    
    793
    +;;
    
    794
    +;; Note also that since both
    
    795
    +;; LEAST-POSITIVE-NORMALIZED-DOUBLE-DOUBLE-FLOAT and
    
    796
    +;; MOST-POSITIVE-DOUBLE-DOUBLE-FLOAT have a low component of 0,
    
    797
    +;; there's no loss of precision if we use the corresponding
    
    798
    +;; DOUBLE-FLOAT values.  Likewise, all the other constants here are
    
    799
    +;; powers of 2, so the DOUBLE-DOUBLE-FLOAT values can be represented
    
    800
    +;; exactly as a DOUBLE-FLOAT.  We can use DOUBLE-FLOAT values.  This
    
    801
    +;; also makes some of the operations a bit simpler since operations
    
    802
    +;; between a DOUBLE-DOUBLE-FLOAT and a DOUBLE-FLOAT are simpler than
    
    803
    +;; if both were DOUBLE-DOUBLE-FLOATs.
    
    804
    +(define-cdiv double-double-float
    
    805
    +  :rmin least-positive-normalized-double-float
    
    806
    +  :rbig (/ most-positive-double-float 2)
    
    807
    +  :rmin2 (scale-float 1d0 -106)
    
    808
    +  :rminscal (scale-float 1d0 102)
    
    809
    +  :eps (scale-float 1d0 -104))
    
    810
    +
    
    826 811
     
    
    827 812
     ;; Smith's algorithm for complex division for (complex single-float).
    
    828 813
     ;; We convert the parts to double-floats before computing the result.
    

  • src/compiler/float-tran-dd.lisp
    ... ... @@ -681,6 +681,18 @@
    681 681
     	(kernel:double-double-hi b)
    
    682 682
     	(kernel:double-double-lo b)))
    
    683 683
     
    
    684
    +(deftransform = ((a b) (vm::double-double-float double-float) *)
    
    685
    +  `(dd= (kernel:double-double-hi a)
    
    686
    +	(kernel:double-double-lo a)
    
    687
    +	b
    
    688
    +	0d0))
    
    689
    +
    
    690
    +(deftransform = ((a b) (double-float vm::double-double-float) *)
    
    691
    +  `(dd= a
    
    692
    +	0d0
    
    693
    +	(kernel:double-double-hi b)
    
    694
    +	(kernel:double-double-lo b)))
    
    695
    +
    
    684 696
     
    
    685 697
     (deftransform < ((a b) (vm::double-double-float vm::double-double-float) *)
    
    686 698
       `(dd< (kernel:double-double-hi a)
    
    ... ... @@ -688,10 +700,34 @@
    688 700
     	(kernel:double-double-hi b)
    
    689 701
     	(kernel:double-double-lo b)))
    
    690 702
     
    
    703
    +(deftransform < ((a b) (vm::double-double-float double-float) *)
    
    704
    +  `(dd< (kernel:double-double-hi a)
    
    705
    +	(kernel:double-double-lo a)
    
    706
    +	b
    
    707
    +	0d0))
    
    708
    +
    
    709
    +(deftransform < ((a b) (double-float vm::double-double-float) *)
    
    710
    +  `(dd< a
    
    711
    +	0d0
    
    712
    +	(kernel:double-double-hi b)
    
    713
    +	(kernel:double-double-lo b)))
    
    714
    +
    
    691 715
     
    
    692 716
     (deftransform > ((a b) (vm::double-double-float vm::double-double-float) *)
    
    693 717
       `(dd> (kernel:double-double-hi a)
    
    694 718
     	(kernel:double-double-lo a)
    
    695 719
     	(kernel:double-double-hi b)
    
    696 720
     	(kernel:double-double-lo b)))
    
    721
    +
    
    722
    +(deftransform > ((a b) (vm::double-double-float double-float) *)
    
    723
    +  `(dd> (kernel:double-double-hi a)
    
    724
    +	(kernel:double-double-lo a)
    
    725
    +	b
    
    726
    +	0d0))
    
    727
    +
    
    728
    +(deftransform > ((a b) (double-float vm::double-double-float) *)
    
    729
    +  `(dd> a
    
    730
    +	0d0
    
    731
    +	(kernel:double-double-hi b)
    
    732
    +	(kernel:double-double-lo b)))
    
    697 733
     ) ; end progn