| ... |
... |
@@ -497,48 +497,65 @@ |
|
497
|
497
|
nil))))))))))))
|
|
498
|
498
|
|
|
499
|
499
|
;;; Ryu ~F
|
|
|
500
|
+(defun emit-fixed (stream rounded is-negative-p w
|
|
|
501
|
+ overflowchar padchar at-sign-p
|
|
|
502
|
+ force-trailing-zero-p value-is-nonzero-p)
|
|
|
503
|
+ "Write a d2fixed result ROUNDED right-justified in W with the usual
|
|
|
504
|
+ ~F padding and overflow rules. FORCE-TRAILING-ZERO-P appends a
|
|
|
505
|
+ single \"0\" after the dot when no fractional digits remain.
|
|
|
506
|
+ VALUE-IS-NONZERO-P enables the leading-\"0\" drop when the field
|
|
|
507
|
+ would otherwise overflow W."
|
|
|
508
|
+ (declare (type simple-string rounded))
|
|
|
509
|
+ (let* ((len (length rounded))
|
|
|
510
|
+ (dot (position #\. rounded))
|
|
|
511
|
+ (int-end (or dot len))
|
|
|
512
|
+ (frac-start (if dot (1+ dot) len))
|
|
|
513
|
+ (frac-len (- len frac-start))
|
|
|
514
|
+ (frac-out-len (cond ((plusp frac-len) frac-len)
|
|
|
515
|
+ (force-trailing-zero-p 1)
|
|
|
516
|
+ (t 0)))
|
|
|
517
|
+ (sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
|
518
|
+ ;; CLHS 22.3.3.1: the leading "0" before the dot is optional
|
|
|
519
|
+ ;; when the magnitude is < 1 (integer part is exactly "0")
|
|
|
520
|
+ ;; and the original value is nonzero. Require something to be
|
|
|
521
|
+ ;; written after the dot so we never drop down to just ".".
|
|
|
522
|
+ (leading-zero-droppable
|
|
|
523
|
+ (and (= int-end 1)
|
|
|
524
|
+ (char= (char rounded 0) #\0)
|
|
|
525
|
+ value-is-nonzero-p
|
|
|
526
|
+ (plusp frac-out-len)))
|
|
|
527
|
+ (full-len (+ sign-len int-end 1 frac-out-len))
|
|
|
528
|
+ (drop-leading-zero-p
|
|
|
529
|
+ (and leading-zero-droppable w (> full-len w)))
|
|
|
530
|
+ (field-len (if drop-leading-zero-p (1- full-len) full-len)))
|
|
|
531
|
+ (flet ((write-field ()
|
|
|
532
|
+ (cond (is-negative-p (write-char #\- stream))
|
|
|
533
|
+ (at-sign-p (write-char #\+ stream)))
|
|
|
534
|
+ (unless drop-leading-zero-p
|
|
|
535
|
+ (write-string rounded stream :start 0 :end int-end))
|
|
|
536
|
+ (write-char #\. stream)
|
|
|
537
|
+ (cond ((plusp frac-len)
|
|
|
538
|
+ (write-string rounded stream :start frac-start :end len))
|
|
|
539
|
+ (force-trailing-zero-p
|
|
|
540
|
+ (write-char #\0 stream)))))
|
|
|
541
|
+ (declare (dynamic-extent #'write-field))
|
|
|
542
|
+ (pad-overflow stream field-len w overflowchar padchar #'write-field))))
|
|
|
543
|
+
|
|
500
|
544
|
(defun format-f-fixed (stream value w d
|
|
501
|
545
|
overflowchar padchar at-sign-p)
|
|
502
|
|
- "Write the ~F representation of VALUE rounded to D digits after the
|
|
503
|
|
- decimal point, right-justified in a field of width W."
|
|
504
|
|
- (declare (type (or single-float double-float) value))
|
|
|
546
|
+ "Write the ~F representation of VALUE rounded to exactly D digits
|
|
|
547
|
+ after the decimal point, right-justified in a field of width W.
|
|
|
548
|
+ This is the explicit-D path: no \"single zero\" rule applies, so
|
|
|
549
|
+ D=0 yields \"d.\" with nothing after the dot. The optional
|
|
|
550
|
+ leading zero before the decimal point is dropped when keeping it
|
|
|
551
|
+ would overflow W (CLHS 22.3.3.1; FORMAT.F.13)."
|
|
|
552
|
+ (declare (type (or single-float double-float) value)
|
|
|
553
|
+ (type (integer 0 *) d))
|
|
505
|
554
|
(multiple-value-bind (is-negative-p abs-value)
|
|
506
|
555
|
(get-sign-and-absolute-value value)
|
|
507
|
|
- (let* ((raw-string (d2fixed abs-value d))
|
|
508
|
|
- (raw-len (length raw-string))
|
|
509
|
|
- (sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
510
|
|
- (need-dot (zerop d))
|
|
511
|
|
- (full-field-len (+ sign-len raw-len (if need-dot 1 0)))
|
|
512
|
|
- ;; CLHS 22.3.3.1: the leading zero before the decimal point
|
|
513
|
|
- ;; is optional when the magnitude is nonzero and less than 1.
|
|
514
|
|
- ;; d2fixed always emits it (e.g. "0.50" for 0.5), so detect
|
|
515
|
|
- ;; that case here and drop the zero if the field would not
|
|
516
|
|
- ;; otherwise fit in W. For exact zero the leading digit is
|
|
517
|
|
- ;; required, so PLUSP ABS-VALUE gates the dropping.
|
|
518
|
|
- (leading-zero-droppable
|
|
519
|
|
- (and (plusp abs-value)
|
|
520
|
|
- (>= raw-len 2)
|
|
521
|
|
- (char= (char raw-string 0) #\0)
|
|
522
|
|
- (char= (char raw-string 1) #\.)))
|
|
523
|
|
- ;; Drop the leading zero if we it's droppable and W is
|
|
524
|
|
- ;; given and the number won't fit in width W field.
|
|
525
|
|
- (drop-leading-zero-p
|
|
526
|
|
- (and leading-zero-droppable
|
|
527
|
|
- w
|
|
528
|
|
- (> full-field-len w)))
|
|
529
|
|
- (field-len (if drop-leading-zero-p
|
|
530
|
|
- (1- full-field-len)
|
|
531
|
|
- full-field-len)))
|
|
532
|
|
- (flet ((write-field ()
|
|
533
|
|
- (cond (is-negative-p (write-char #\- stream))
|
|
534
|
|
- (at-sign-p (write-char #\+ stream)))
|
|
535
|
|
- (cond (drop-leading-zero-p
|
|
536
|
|
- (write-string raw-string stream :start 1))
|
|
537
|
|
- (t
|
|
538
|
|
- (write-string raw-string stream)))
|
|
539
|
|
- (when need-dot (write-char #\. stream))))
|
|
540
|
|
- (declare (dynamic-extent #'write-field))
|
|
541
|
|
- (pad-overflow stream field-len w overflowchar padchar #'write-field)))))
|
|
|
556
|
+ (emit-fixed stream (d2fixed abs-value d) is-negative-p w
|
|
|
557
|
+ overflowchar padchar at-sign-p nil
|
|
|
558
|
+ (plusp abs-value))))
|
|
542
|
559
|
|
|
543
|
560
|
(defun reshape-fixed-length (digit-count exponent)
|
|
544
|
561
|
;; DIGIT-COUNT is the number of digits returned by d2s/f2s. That no
|
| ... |
... |
@@ -583,62 +600,11 @@ |
|
583
|
600
|
(declare (dynamic-extent #'write-field))
|
|
584
|
601
|
(pad-overflow stream field-len w overflowchar padchar #'write-field))))
|
|
585
|
602
|
|
|
586
|
|
-(defun emit-rounded-to-width (stream value frac is-negative-p w
|
|
587
|
|
- overflowchar padchar at-sign-p)
|
|
588
|
|
- "Round (the magnitude of) VALUE to FRAC fractional digits with
|
|
589
|
|
- d2fixed and write it right-justified in a field of width W. At
|
|
590
|
|
- least one fractional digit is always shown: if FRAC is 0 the
|
|
591
|
|
- rounded value is integral and a single \"0\" is appended after the
|
|
592
|
|
- decimal point (CLHS 22.3.3.1). The leading zero before the
|
|
593
|
|
- decimal point is kept when the field fits in W (FORMAT.F.47) and
|
|
594
|
|
- dropped when keeping it would overflow W (FORMAT.F.46). Used by
|
|
595
|
|
- the free-format ~F path when the shortest representation does not
|
|
596
|
|
- fit in W."
|
|
597
|
|
- (declare (type (or single-float double-float) value)
|
|
598
|
|
- (type (integer 0 *) frac))
|
|
599
|
|
- (let* ((rounded (d2fixed (float (abs value) 1d0) frac))
|
|
600
|
|
- (len (length rounded))
|
|
601
|
|
- ;; ROUNDED is "ddd" (frac=0) or "ddd.ddd" (frac>0). Locate the
|
|
602
|
|
- ;; decimal point and the integer/fractional digit spans without
|
|
603
|
|
- ;; allocating substrings.
|
|
604
|
|
- (dot (position #\. rounded))
|
|
605
|
|
- (int-end (or dot len))
|
|
606
|
|
- (frac-start (if dot (1+ dot) len))
|
|
607
|
|
- (frac-len (- len frac-start))
|
|
608
|
|
- ;; At least one fractional digit is always shown; when there are
|
|
609
|
|
- ;; none a single "0" is emitted instead.
|
|
610
|
|
- (frac-out-len (max 1 frac-len))
|
|
611
|
|
- (sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
612
|
|
- ;; The leading "0." may be shortened to "." when the magnitude
|
|
613
|
|
- ;; is < 1 (integer part is the single digit "0") and nonzero,
|
|
614
|
|
- ;; and only when the full field would not fit in W.
|
|
615
|
|
- (leading-zero-droppable
|
|
616
|
|
- (and (= int-end 1)
|
|
617
|
|
- (char= (char rounded 0) #\0)
|
|
618
|
|
- (not (zerop value))))
|
|
619
|
|
- (full-len (+ sign-len int-end 1 frac-out-len))
|
|
620
|
|
- (drop-leading-zero-p
|
|
621
|
|
- (and leading-zero-droppable w (> full-len w)))
|
|
622
|
|
- (field-len (if drop-leading-zero-p (1- full-len) full-len)))
|
|
623
|
|
- (flet ((write-field ()
|
|
624
|
|
- (cond (is-negative-p (write-char #\- stream))
|
|
625
|
|
- (at-sign-p (write-char #\+ stream)))
|
|
626
|
|
- (unless drop-leading-zero-p
|
|
627
|
|
- (write-string rounded stream :start 0 :end int-end))
|
|
628
|
|
- (write-char #\. stream)
|
|
629
|
|
- (cond ((zerop frac-len)
|
|
630
|
|
- (write-char #\0 stream))
|
|
631
|
|
- (t
|
|
632
|
|
- (write-string rounded stream :start frac-start :end len)))))
|
|
633
|
|
- (declare (dynamic-extent #'write-field))
|
|
634
|
|
- (pad-overflow stream field-len w overflowchar padchar #'write-field))))
|
|
635
|
|
-
|
|
636
|
603
|
(defun format-f-free (stream value w
|
|
637
|
604
|
overflowchar padchar at-sign-p)
|
|
638
|
605
|
(declare (type (or single-float double-float) value))
|
|
639
|
606
|
(multiple-value-bind (is-negative-p abs-value)
|
|
640
|
607
|
(get-sign-and-absolute-value value)
|
|
641
|
|
- (declare (ignore abs-value))
|
|
642
|
608
|
(multiple-value-bind (mantissa exponent)
|
|
643
|
609
|
(parsed-exp-form (float-to-string value))
|
|
644
|
610
|
(let* ((digit-count (mantissa-digit-count mantissa))
|
| ... |
... |
@@ -658,16 +624,15 @@ |
|
658
|
624
|
(loop repeat w
|
|
659
|
625
|
do (write-char overflowchar stream)))
|
|
660
|
626
|
(t
|
|
661
|
|
- ;; The shortest form does not fit in W. D was not specified,
|
|
662
|
|
- ;; so round the value to the largest number of fractional
|
|
663
|
|
- ;; digits D-FIT that fits, then display it. Per CLHS 22.3.3.1,
|
|
664
|
|
- ;; if the fraction rounds away to nothing a single zero digit
|
|
665
|
|
- ;; must still appear after the decimal point. EMIT-ROUNDED-TO-
|
|
666
|
|
- ;; WIDTH may drop the leading "0" before the dot if keeping it
|
|
667
|
|
- ;; would still overflow W.
|
|
668
|
|
- (emit-rounded-to-width stream value (max 0 d-fit)
|
|
669
|
|
- is-negative-p w
|
|
670
|
|
- overflowchar padchar at-sign-p)))))))
|
|
|
627
|
+ ;; The shortest form does not fit in W. Round to the largest
|
|
|
628
|
+ ;; number of fractional digits D-FIT that fits and emit via
|
|
|
629
|
+ ;; EMIT-FIXED, forcing a trailing "0" if the fraction rounds
|
|
|
630
|
+ ;; away (CLHS 22.3.3.1; FORMAT.F.46 may drop the leading "0"
|
|
|
631
|
+ ;; before the dot if keeping it would still overflow W).
|
|
|
632
|
+ (emit-fixed stream
|
|
|
633
|
+ (d2fixed abs-value (max 0 d-fit))
|
|
|
634
|
+ is-negative-p w overflowchar padchar at-sign-p
|
|
|
635
|
+ t (plusp abs-value))))))))
|
|
671
|
636
|
|
|
672
|
637
|
(defun format-f (stream value w d k overflowchar padchar at-sign-p)
|
|
673
|
638
|
(declare (type (or single-float double-float) value)
|