Raymond Toy pushed to branch rtoy-print-using-ryu at cmucl / cmucl

Commits:

6 changed files:

Changes:

  • src/code/format.lisp
    ... ... @@ -1583,9 +1583,9 @@
    1583 1583
       ;; DOUBLE-DOUBLE-FLOAT) always falls through to the B&D path.
    
    1584 1584
       (cond
    
    1585 1585
         ((and lisp::*use-ryu-printer*
    
    1586
    -	  (and k (zerop k))
    
    1586
    +	  (or (null k) (zerop k))
    
    1587 1587
     	  (typep number '(or single-float double-float)))
    
    1588
    -     (format-fixed-ryu stream number w d k ovf pad atsign))
    
    1588
    +     (format-fixed-ryu stream number w d (or k 0) ovf pad atsign))
    
    1589 1589
         (t
    
    1590 1590
          (format-fixed-aux-bd stream number w d k ovf pad atsign))))
    
    1591 1591
     
    
    ... ... @@ -1971,7 +1971,7 @@
    1971 1971
         (prin1 number stream)
    
    1972 1972
         nil)
    
    1973 1973
        (t
    
    1974
    -    (write-string (lisp::format-g number w d e k ovf pad marker atsign)
    
    1974
    +    (write-string (lisp::format-g number w d e (or k 1) ovf pad marker atsign)
    
    1975 1975
     		  stream)))
    
    1976 1976
       (values))
    
    1977 1977
     
    

  • src/code/print.lisp
    ... ... @@ -2001,6 +2001,67 @@ radix-R. If you have a power-list then pass it in as PL."
    2001 2001
     
    
    2002 2002
     
    
    2003 2003
     (defun output-float-aux (x stream e-min e-max)
    
    2004
    +  ;; Dispatch to either the Burger and Dybvig implementation or the
    
    2005
    +  ;; Ryu-based implementation.  The Ryu code only handles single- and
    
    2006
    +  ;; double-float values, so any other float type (notably
    
    2007
    +  ;; DOUBLE-DOUBLE-FLOAT) always falls through to the B&D path.
    
    2008
    +  (cond
    
    2009
    +    ((and *use-ryu-printer*
    
    2010
    +	  (typep x '(or single-float double-float)))
    
    2011
    +     (output-float-ryu x stream e-min e-max))
    
    2012
    +    (t
    
    2013
    +     (output-float-aux-bd x stream e-min e-max))))
    
    2014
    +
    
    2015
    +(defun output-float-ryu (x stream e-min e-max)
    
    2016
    +  "Ryu-based implementation of free-format float printing.  Uses
    
    2017
    +  FLOAT-TO-STRING (D2S/F2S) to obtain the shortest round-tripping digit
    
    2018
    +  string, then dispatches on the exponent to either free or exponential
    
    2019
    +  notation, matching the layout produced by OUTPUT-FLOAT-AUX-BD."
    
    2020
    +  (multiple-value-bind (mantissa actual-exp)
    
    2021
    +      (parsed-exp-form (float-to-string x))
    
    2022
    +    ;; MANTISSA is "d.ddd"; strip the decimal point so STRING is just
    
    2023
    +    ;; the digit run, matching the second value of FLONUM-TO-DIGITS.
    
    2024
    +    ;; The B&D convention is that the value equals 0.STRING * 10^E,
    
    2025
    +    ;; so E = ACTUAL-EXP + 1 (mantissa "d.ddd" has the point one
    
    2026
    +    ;; position right of the implicit "0.").
    
    2027
    +    (let* ((dot-pos (position #\. mantissa))
    
    2028
    +	   (string (if dot-pos
    
    2029
    +		       (concatenate 'string
    
    2030
    +				    (subseq mantissa 0 dot-pos)
    
    2031
    +				    (subseq mantissa (1+ dot-pos)))
    
    2032
    +		       mantissa))
    
    2033
    +	   (e (1+ actual-exp)))
    
    2034
    +      (cond
    
    2035
    +	((< e-min e e-max)
    
    2036
    +	 ;; free format
    
    2037
    +	 (cond ((plusp e)
    
    2038
    +		(write-string string stream :end (min (length string) e))
    
    2039
    +		(dotimes (i (- e (length string)))
    
    2040
    +		  (write-char #\0 stream))
    
    2041
    +		(write-char #\. stream)
    
    2042
    +		(write-string string stream :start (min (length string) e))
    
    2043
    +		(when (<= (length string) e)
    
    2044
    +		  (write-char #\0 stream))
    
    2045
    +		(print-float-exponent x 0 stream))
    
    2046
    +	       (t
    
    2047
    +		(write-string "0." stream)
    
    2048
    +		(dotimes (i (- e))
    
    2049
    +		  (write-char #\0 stream))
    
    2050
    +		(write-string string stream)
    
    2051
    +		(print-float-exponent x 0 stream))))
    
    2052
    +	(t
    
    2053
    +	 ;; Exponential format
    
    2054
    +	 (write-string string stream :end 1)
    
    2055
    +	 (write-char #\. stream)
    
    2056
    +	 (write-string string stream :start 1)
    
    2057
    +	 ;; CLHS 22.1.3.1.3 says at least one digit must be printed
    
    2058
    +	 ;; after the decimal point.
    
    2059
    +	 (when (= (length string) 1)
    
    2060
    +	   (write-char #\0 stream))
    
    2061
    +	 (print-float-exponent x (1- e) stream))))))
    
    2062
    +
    
    2063
    +(defun output-float-aux-bd (x stream e-min e-max)
    
    2064
    +  "Burger and Dybvig based implementation of free-format float printing."
    
    2004 2065
       (multiple-value-bind (e string)
    
    2005 2066
           (flonum-to-digits x)
    
    2006 2067
         (cond
    

  • src/i18n/locale/cmucl.pot
    No preview for this file type
  • src/tools/worldbuild.lisp
    ... ... @@ -156,8 +156,8 @@
    156 156
         "target:code/serve-event"
    
    157 157
         "target:code/stream"
    
    158 158
         "target:code/fd-stream"
    
    159
    -    "target:code/print"
    
    160 159
         "target:code/ryu-print"
    
    160
    +    "target:code/print"
    
    161 161
         "target:code/pprint"
    
    162 162
         "target:code/format"
    
    163 163
         "target:code/package"
    

  • src/tools/worldcom.lisp
    ... ... @@ -237,8 +237,8 @@
    237 237
     (comf "target:code/save")
    
    238 238
     
    
    239 239
     (comf "target:code/stream")
    
    240
    -(comf "target:code/print")
    
    241 240
     (comf "target:code/ryu-print")
    
    241
    +(comf "target:code/print")
    
    242 242
     (comf "target:code/pprint")
    
    243 243
     #-no-runtime (comf "target:code/pprint" :byte-compile t)
    
    244 244
     (comf "target:code/pprint-loop")
    

  • tests/ryu.lisp
    ... ... @@ -986,3 +986,75 @@
    986 986
         (assert-true (stringp (format nil "~G" 1/2)))
    
    987 987
         (assert-true (stringp (format nil "~G" 1)))))
    
    988 988
     
    
    989
    +;;; ----------------------------------------------------------------------
    
    990
    +;;; Tests that the float printer used by PRIN1/PRINC/PRINT/WRITE
    
    991
    +;;; (i.e. OUTPUT-FLOAT-AUX) dispatches through Ryu when
    
    992
    +;;; *use-ryu-printer* is set.  Both code paths should produce
    
    993
    +;;; round-trippable strings.  We don't assert character equality
    
    994
    +;;; between the two paths because the shortest round-tripping digit
    
    995
    +;;; sequence is allowed to differ in rounding of the tie case; we do
    
    996
    +;;; assert each path round-trips.
    
    997
    +
    
    998
    +(define-test output-float.dispatch.round-trip
    
    999
    +  (:tag :output-float :dispatch)
    
    1000
    +  (let ((values '(3.14d0
    
    1001
    +		  -3.14d0
    
    1002
    +		  0.1d0
    
    1003
    +		  1.0d100
    
    1004
    +		  1.0d-100
    
    1005
    +		  1.0d0
    
    1006
    +		  3.14f0
    
    1007
    +		  -3.14f0
    
    1008
    +		  0.1f0)))
    
    1009
    +    (dolist (v values)
    
    1010
    +      (let ((with-ryu
    
    1011
    +	      (let ((lisp::*use-ryu-printer* t))
    
    1012
    +		(prin1-to-string v)))
    
    1013
    +	    (without-ryu
    
    1014
    +	      (let ((lisp::*use-ryu-printer* nil))
    
    1015
    +		(prin1-to-string v))))
    
    1016
    +	(assert-equal v (read-from-string with-ryu) v with-ryu)
    
    1017
    +	(assert-equal v (read-from-string without-ryu) v without-ryu)))))
    
    1018
    +
    
    1019
    +(define-test output-float.dispatch.princ-matches-prin1
    
    1020
    +  (:tag :output-float :dispatch)
    
    1021
    +  ;; For floats, PRIN1 and PRINC produce the same string (floats don't
    
    1022
    +  ;; have escape characters).  This should hold under both code paths.
    
    1023
    +  (let ((lisp::*use-ryu-printer* t))
    
    1024
    +    (assert-equal (prin1-to-string 3.14d0)
    
    1025
    +                  (princ-to-string 3.14d0))
    
    1026
    +    (assert-equal (prin1-to-string 3.14f0)
    
    1027
    +                  (princ-to-string 3.14f0))))
    
    1028
    +
    
    1029
    +(define-test output-float.dispatch.zero
    
    1030
    +  (:tag :output-float :dispatch)
    
    1031
    +  ;; Zero is handled by OUTPUT-FLOAT itself (not OUTPUT-FLOAT-AUX), so
    
    1032
    +  ;; the dispatch is never reached.  Still, make sure both settings
    
    1033
    +  ;; produce identical output.
    
    1034
    +  (let ((with-ryu
    
    1035
    +	  (let ((lisp::*use-ryu-printer* t))
    
    1036
    +	    (prin1-to-string 0.0d0)))
    
    1037
    +	(without-ryu
    
    1038
    +	  (let ((lisp::*use-ryu-printer* nil))
    
    1039
    +	    (prin1-to-string 0.0d0))))
    
    1040
    +    (assert-equal without-ryu with-ryu)))
    
    1041
    +
    
    1042
    +(define-test output-float.dispatch.special-values
    
    1043
    +  (:tag :output-float :dispatch)
    
    1044
    +  ;; Infinity and NaN are handled in OUTPUT-FLOAT itself, before the
    
    1045
    +  ;; OUTPUT-FLOAT-AUX dispatch, so the Ryu path is not exercised.
    
    1046
    +  ;; Verify no error.
    
    1047
    +  (let ((lisp::*use-ryu-printer* t))
    
    1048
    +    (assert-true (stringp (prin1-to-string
    
    1049
    +                            ext:double-float-positive-infinity)))))
    
    1050
    +
    
    1051
    +(define-test output-float.dispatch.double-double
    
    1052
    +  (:tag :output-float :dispatch)
    
    1053
    +  ;; DOUBLE-DOUBLE-FLOAT is handled in OUTPUT-FLOAT itself when the
    
    1054
    +  ;; feature is enabled (currently behind #+(and nil double-double),
    
    1055
    +  ;; i.e. inactive), so it actually reaches OUTPUT-FLOAT-AUX.  Confirm
    
    1056
    +  ;; the type-guard in the dispatch wrapper sends it to the B&D path.
    
    1057
    +  #+double-double
    
    1058
    +  (let ((lisp::*use-ryu-printer* t))
    
    1059
    +    (assert-true (stringp (prin1-to-string 1w0)))))
    
    1060
    +