Raymond Toy pushed to branch rtoy-print-using-ryu at cmucl / cmucl
Commits:
-
c841c128
by Raymond Toy at 2026-05-28T15:31:14-07:00
2 changed files:
Changes:
| ... | ... | @@ -142,7 +142,7 @@ |
| 142 | 142 | (declare (fixnum k actual-exp))
|
| 143 | 143 | (let* ((sign-len (if (or is-negative-p at-sign-p) 1 0))
|
| 144 | 144 | (exp-digits (max (or e 1)
|
| 145 | - (length (princ-to-string (abs actual-exp)))))
|
|
| 145 | + (count-decimal-digits (abs actual-exp))))
|
|
| 146 | 146 | ;; The min output includes the leading sign, and the length
|
| 147 | 147 | ;; of the exponent. If k > 0, we have a leading digit, a
|
| 148 | 148 | ;; dot, the exponent marker and exponent sign for 4 extra.
|
| ... | ... | @@ -389,16 +389,48 @@ |
| 389 | 389 | (t
|
| 390 | 390 | (let* ((d-fit (compute-d-for-width w e k actual-exp is-negative-p at-sign-p))
|
| 391 | 391 | (drop-zero-p (and d-fit (<= k 0))))
|
| 392 | - (if d-fit
|
|
| 393 | - (multiple-value-bind (mantissa exponent)
|
|
| 394 | - (parsed-exp-form (d2exp abs-value
|
|
| 392 | + (cond
|
|
| 393 | + (d-fit
|
|
| 394 | + (multiple-value-bind (mantissa exponent)
|
|
| 395 | + (parsed-exp-form (d2exp abs-value
|
|
| 395 | 396 | (d2exp-precision d-fit k)))
|
| 396 | - (format-e-string stream mantissa exponent is-negative-p
|
|
| 397 | - w e k overflowchar padchar exponentchar at-sign-p
|
|
| 398 | - drop-zero-p))
|
|
| 399 | - (format-e-string stream mantissa exponent is-negative-p
|
|
| 400 | - w e k overflowchar padchar exponentchar at-sign-p
|
|
| 401 | - nil))))))))))))
|
|
| 397 | + (format-e-string stream mantissa exponent is-negative-p
|
|
| 398 | + w e k overflowchar padchar exponentchar at-sign-p
|
|
| 399 | + drop-zero-p)))
|
|
| 400 | + (overflowchar
|
|
| 401 | + ;; Not even the no-fractional-digit form fits and
|
|
| 402 | + ;; an overflow char was supplied: fill W.
|
|
| 403 | + (loop repeat w do (write-char overflowchar stream)))
|
|
| 404 | + ((= k 1)
|
|
| 405 | + ;; No fractional digit fits. Emit "[d].e[exp]"
|
|
| 406 | + ;; directly -- no forced ".0". CLHS 22.3.3.2
|
|
| 407 | + ;; "single zero digit ... if the width w permits";
|
|
| 408 | + ;; here it does not, so the field overflows W.
|
|
| 409 | + ;; Handled only for k=1 (default); other k values
|
|
| 410 | + ;; fall through to the old format-e-string path.
|
|
| 411 | + (multiple-value-bind (one-digit shown-exp)
|
|
| 412 | + (parsed-exp-form (d2exp abs-value 0))
|
|
| 413 | + (let* ((exp-sign (if (minusp shown-exp) #\- #\+))
|
|
| 414 | + (exp-abs (abs shown-exp))
|
|
| 415 | + (exp-digits (count-decimal-digits exp-abs))
|
|
| 416 | + (exp-width (max (or e 1) exp-digits))
|
|
| 417 | + (exp-marker (or exponentchar #\d)))
|
|
| 418 | + (cond (is-negative-p (write-char #\- stream))
|
|
| 419 | + (at-sign-p (write-char #\+ stream)))
|
|
| 420 | + (write-string one-digit stream)
|
|
| 421 | + (write-char #\. stream)
|
|
| 422 | + (write-char exp-marker stream)
|
|
| 423 | + (write-char exp-sign stream)
|
|
| 424 | + (loop repeat (- exp-width exp-digits)
|
|
| 425 | + do (write-char #\0 stream))
|
|
| 426 | + (princ exp-abs stream))))
|
|
| 427 | + (t
|
|
| 428 | + ;; k != 1 and no width fits: fall back to the
|
|
| 429 | + ;; shortest form (may still emit a forced ".0";
|
|
| 430 | + ;; rare, not yet handled).
|
|
| 431 | + (format-e-string stream mantissa exponent is-negative-p
|
|
| 432 | + w e k overflowchar padchar exponentchar at-sign-p
|
|
| 433 | + nil)))))))))))))
|
|
| 402 | 434 | |
| 403 | 435 | ;;; Ryu ~F
|
| 404 | 436 | (defun format-f-fixed (stream value w d
|
| ... | ... | @@ -288,6 +288,24 @@ |
| 288 | 288 | (assert-equal "0.0d+0"
|
| 289 | 289 | (lisp::format-e 0d0 nil nil nil 1 nil nil #\d nil)))
|
| 290 | 290 | |
| 291 | +(define-test format-e.tight-width-no-fraction
|
|
| 292 | + (:tag :format-e)
|
|
| 293 | + ;; ANSI FORMAT.E.4/.5/.7/.8/.9: ~Ne with N too small for the
|
|
| 294 | + ;; "d.0e+0" shortest form drops the fractional digit instead of
|
|
| 295 | + ;; forcing the ".0", giving "d.e+0" (overflowing W when even that
|
|
| 296 | + ;; form is wider). CLHS 22.3.3.2 "single zero digit ... if the
|
|
| 297 | + ;; width w permits" -- here it does not.
|
|
| 298 | + (assert-equal "1.e+0"
|
|
| 299 | + (lisp::format-e 1.0f0 5 nil nil 1 nil nil #\e nil))
|
|
| 300 | + (assert-equal "1.e+0"
|
|
| 301 | + (lisp::format-e 1.0f0 4 nil nil 1 nil nil #\e nil))
|
|
| 302 | + (assert-equal "+1.e+0"
|
|
| 303 | + (lisp::format-e 1.0f0 6 nil nil 1 nil nil #\e t))
|
|
| 304 | + (assert-equal "+1.e+0"
|
|
| 305 | + (lisp::format-e 1.0f0 5 nil nil 1 nil nil #\e t))
|
|
| 306 | + (assert-equal "-1.e+0"
|
|
| 307 | + (lisp::format-e -1.0f0 6 nil nil 1 nil nil #\e nil)))
|
|
| 308 | + |
|
| 291 | 309 | ;;; ~F tests
|
| 292 | 310 | (define-test format-f.basic
|
| 293 | 311 | (:tag :format-f)
|