| ... |
... |
@@ -2107,7 +2107,8 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2107
|
2107
|
((< n 100) 2)
|
|
2108
|
2108
|
(t 3)))
|
|
2109
|
2109
|
|
|
2110
|
|
-(defun compute-exp-output-length (mantissa actual-exp k e is-negative-p at-sign-p drop-leading-zero-p)
|
|
|
2110
|
+(defun compute-exp-output-length (mantissa actual-exp k e is-negative-p at-sign-p
|
|
|
2111
|
+ drop-leading-zero-p)
|
|
2111
|
2112
|
;; Compute length of the ~E result with the given parameters, but
|
|
2112
|
2113
|
;; don't build the string. MANTISSA is "d[.dddd]" from d2exp or d2s.
|
|
2113
|
2114
|
;; ACTUAL-EXP is the exponent with scaling factor applied. If
|
| ... |
... |
@@ -2138,77 +2139,6 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2138
|
2139
|
;; +2 for the exponent marker and sign
|
|
2139
|
2140
|
(+ sign-len mantissa-len exp-digits 2)))
|
|
2140
|
2141
|
|
|
2141
|
|
-#+nil
|
|
2142
|
|
-(defun reshape-format-e (mantissa-text k drop-leading-zero-p)
|
|
2143
|
|
- "Reshape MANTISSA-TEXT of the form 'd[.dddd]Eee' from d2s or d2exp into
|
|
2144
|
|
- the displayed mantissa for ~E with scale factor K. If
|
|
2145
|
|
- DROP-LEADING-ZERO-P is non-NIL, the leading 0 that would have been
|
|
2146
|
|
- printed is dropped."
|
|
2147
|
|
- (declare (type simple-string mantissa-text)
|
|
2148
|
|
- (fixnum k))
|
|
2149
|
|
- ;; Fast path: K=1 covers the overwhelmingly common case since K=1 is
|
|
2150
|
|
- ;; the default.
|
|
2151
|
|
- (when (= k 1)
|
|
2152
|
|
- (return-from reshape-format-e
|
|
2153
|
|
- (cond
|
|
2154
|
|
- ((find #\. mantissa-text)
|
|
2155
|
|
- mantissa-text) ; verbatim
|
|
2156
|
|
- (t
|
|
2157
|
|
- (concatenate 'string mantissa-text ".0"))))) ; single digit -> "D.0"
|
|
2158
|
|
- (let* ((has-dot (find #\. mantissa-text))
|
|
2159
|
|
- (lead-char (char mantissa-text 0))
|
|
2160
|
|
- ;; Where the stuff after the dot starts
|
|
2161
|
|
- (tail-start (if has-dot 2 1))
|
|
2162
|
|
- (tail-len (- (length mantissa-text) tail-start))
|
|
2163
|
|
- (digit-count (1+ tail-len)))
|
|
2164
|
|
- ;; Several cases to consider:
|
|
2165
|
|
- ;;
|
|
2166
|
|
- ;; * k is negative so the new dot preceeds the mantissa. Pad with
|
|
2167
|
|
- ;; zeroes.
|
|
2168
|
|
- ;; * k is so large that the dot is past the rightmost part of the
|
|
2169
|
|
- ;; mantissa. Append enough zeroes and then add ".0"
|
|
2170
|
|
- ;; * k is somewhere in the mantissa. Handling of this case
|
|
2171
|
|
- ;; depends on if the new dot is to the left or to the right of
|
|
2172
|
|
- ;; the original dot.
|
|
2173
|
|
- (with-output-to-string (s)
|
|
2174
|
|
- (cond
|
|
2175
|
|
- ;; Case 2: new dot at or before position 0.
|
|
2176
|
|
- ((<= k 0)
|
|
2177
|
|
- (unless drop-leading-zero-p
|
|
2178
|
|
- (write-char #\0 s))
|
|
2179
|
|
- (write-char #\. s)
|
|
2180
|
|
- ;; Insert zeros after the decimal but before the mantissa.
|
|
2181
|
|
- (loop repeat (- k)
|
|
2182
|
|
- do (write-char #\0 s))
|
|
2183
|
|
- ;; Insert the mantissa, skipping the existing dot.
|
|
2184
|
|
- (write-char lead-char s)
|
|
2185
|
|
- (when (plusp tail-len)
|
|
2186
|
|
- (write-string mantissa-text s :start tail-start)))
|
|
2187
|
|
- ;; Case 1b: 1 < k < digit-count. Move dot right by (k-1).
|
|
2188
|
|
- ((< k digit-count)
|
|
2189
|
|
- ;; Output the original mantissa up to the original dot.
|
|
2190
|
|
- (write-char lead-char s)
|
|
2191
|
|
- (write-string mantissa-text s
|
|
2192
|
|
- :start tail-start
|
|
2193
|
|
- :end (+ tail-start k -1))
|
|
2194
|
|
- ;; Output the new dot.
|
|
2195
|
|
- (write-char #\. s)
|
|
2196
|
|
- ;; Output everything after the original dot.
|
|
2197
|
|
- (write-string mantissa-text s
|
|
2198
|
|
- :start (+ tail-start k -1)))
|
|
2199
|
|
- ;; Case 3: k >= digit-count. Pad with zeros, force ".0".
|
|
2200
|
|
- (t
|
|
2201
|
|
- ;; Output the original mantissa, then everything after the
|
|
2202
|
|
- ;; dot (if there was one).
|
|
2203
|
|
- (write-char lead-char s)
|
|
2204
|
|
- (when (plusp tail-len)
|
|
2205
|
|
- (write-string mantissa-text s :start tail-start))
|
|
2206
|
|
- ;; Pad with 0's
|
|
2207
|
|
- (loop repeat (- k digit-count)
|
|
2208
|
|
- do (write-char #\0 s))
|
|
2209
|
|
- ;; Finish with ".0".
|
|
2210
|
|
- (write-string ".0" s))))))
|
|
2211
|
|
-
|
|
2212
|
2142
|
(defun scale-mantissa (stream mantissa-text k drop-leading-zero-p)
|
|
2213
|
2143
|
"Write MANTISSA-TEXT to STREAM, shifting the decimal point so that
|
|
2214
|
2144
|
the new dot lands K digits in from the start of the digit string.
|
| ... |
... |
@@ -2292,56 +2222,6 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2292
|
2222
|
;; d - |k| - 1 digits after the decimal point.
|
|
2293
|
2223
|
(max (+ d k -1) 0))))
|
|
2294
|
2224
|
|
|
2295
|
|
-#+nil
|
|
2296
|
|
-(defun format-e-string (mantissa exponent is-negative-p w e k
|
|
2297
|
|
- overflowchar padchar exponentchar at-sign-p
|
|
2298
|
|
- drop-leading-zero-p)
|
|
2299
|
|
- (declare (type simple-string mantissa)
|
|
2300
|
|
- (fixnum exponent k))
|
|
2301
|
|
- (let* ((shown-exp (- exponent (1- k)))
|
|
2302
|
|
- (exp-sign (if (minusp shown-exp) #\- #\+))
|
|
2303
|
|
- (exp-abs (abs shown-exp))
|
|
2304
|
|
- (exp-marker (or exponentchar #\d))
|
|
2305
|
|
- (exp-string
|
|
2306
|
|
- (with-output-to-string (s)
|
|
2307
|
|
- (write-char exp-marker s)
|
|
2308
|
|
- (write-char exp-sign s)
|
|
2309
|
|
- #+nil
|
|
2310
|
|
- (let ((digits (princ-to-string exp-abs)))
|
|
2311
|
|
- (when e
|
|
2312
|
|
- (loop repeat (- e (length digits))
|
|
2313
|
|
- do (write-char #\0 s)))
|
|
2314
|
|
- (write-string digits s))
|
|
2315
|
|
- (let ((d (count-decimal-digits exp-abs)))
|
|
2316
|
|
- (when e
|
|
2317
|
|
- (loop repeat (- e d)
|
|
2318
|
|
- do (write-char #\0 s)))
|
|
2319
|
|
- (princ exp-abs s))))
|
|
2320
|
|
- (sign-mantissa (cond (is-negative-p "-")
|
|
2321
|
|
- (at-sign-p "+")
|
|
2322
|
|
- (t "")))
|
|
2323
|
|
- ;; Reshape once, reuse everywhere.
|
|
2324
|
|
- (reshaped (reshape-format-e mantissa k drop-leading-zero-p))
|
|
2325
|
|
- (field-len (+ (length sign-mantissa)
|
|
2326
|
|
- (length reshaped)
|
|
2327
|
|
- (length exp-string))))
|
|
2328
|
|
- (flet ((write-field (s)
|
|
2329
|
|
- (write-string sign-mantissa s)
|
|
2330
|
|
- (write-string reshaped s)
|
|
2331
|
|
- (write-string exp-string s)))
|
|
2332
|
|
- (with-output-to-string (s)
|
|
2333
|
|
- (cond
|
|
2334
|
|
- ((null w)
|
|
2335
|
|
- (write-field s))
|
|
2336
|
|
- ((> field-len w)
|
|
2337
|
|
- (if overflowchar
|
|
2338
|
|
- (loop repeat w do (write-char overflowchar s))
|
|
2339
|
|
- (write-field s)))
|
|
2340
|
|
- (t
|
|
2341
|
|
- (let ((pad-char (or padchar #\Space)))
|
|
2342
|
|
- (loop repeat (- w field-len) do (write-char pad-char s))
|
|
2343
|
|
- (write-field s))))))))
|
|
2344
|
|
-
|
|
2345
|
2225
|
(defun format-e-string (stream mantissa exponent is-negative-p w e k
|
|
2346
|
2226
|
overflowchar padchar exponentchar at-sign-p
|
|
2347
|
2227
|
drop-leading-zero-p)
|
| ... |
... |
@@ -2379,64 +2259,6 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2379
|
2259
|
(declare (dynamic-extent #'write-field))
|
|
2380
|
2260
|
(pad-overflow stream field-len w overflowchar padchar #'write-field))))
|
|
2381
|
2261
|
|
|
2382
|
|
-#+nil
|
|
2383
|
|
-(defun format-e (value w d e k overflowchar padchar exponentchar at-sign-p)
|
|
2384
|
|
- (declare (double-float value)
|
|
2385
|
|
- (fixnum k)
|
|
2386
|
|
- (type (or null (and unsigned-byte fixnum)) w d e)
|
|
2387
|
|
- (optimize (speed 3)))
|
|
2388
|
|
- (let* ((is-negative-p (minusp (float-sign value)))
|
|
2389
|
|
- (abs-value (abs value)))
|
|
2390
|
|
- (cond
|
|
2391
|
|
- (d
|
|
2392
|
|
- ;; Fixed precision path. Leading 0 is kept.
|
|
2393
|
|
- (multiple-value-bind (mantissa exponent)
|
|
2394
|
|
- (parsed-exp-form (d2exp abs-value (d2exp-precision d k)))
|
|
2395
|
|
- (format-e-string mantissa exponent is-negative-p
|
|
2396
|
|
- w e k overflowchar padchar exponentchar at-sign-p nil)))
|
|
2397
|
|
- (t
|
|
2398
|
|
- ;; Free-format path. Use d2s to find the shortest result. If
|
|
2399
|
|
- ;; it won't fit in the given format parameters, compute a new d
|
|
2400
|
|
- ;; value to make it fit in the given width if possible.
|
|
2401
|
|
- ;; Otherwise, overflow.
|
|
2402
|
|
- (multiple-value-bind (mantissa exponent)
|
|
2403
|
|
- (parsed-exp-form (d2s abs-value))
|
|
2404
|
|
- (let* ((actual-exp (- exponent (1- k)))
|
|
2405
|
|
- (full-len (compute-exp-output-length mantissa actual-exp k e is-negative-p at-sign-p
|
|
2406
|
|
- nil)))
|
|
2407
|
|
- #+nil
|
|
2408
|
|
- (format t "mantissa = ~A exponent = ~D actual-exp = ~D full-len = ~D w = ~D~%"
|
|
2409
|
|
- mantissa exponent actual-exp full-len w)
|
|
2410
|
|
- (cond
|
|
2411
|
|
- ((or (null w) (<= full-len w))
|
|
2412
|
|
- ;; Shortest fits. Emit it. Drop the leading 0 whenever
|
|
2413
|
|
- ;; k <= 0 so the actual emitted legnth matches the
|
|
2414
|
|
- ;; predicted one.
|
|
2415
|
|
- (format-e-string mantissa exponent is-negative-p
|
|
2416
|
|
- w e k overflowchar padchar exponentchar at-sign-p
|
|
2417
|
|
- (not (plusp k))))
|
|
2418
|
|
- (t
|
|
2419
|
|
- ;; Doesn't fit. Compute the largest fitting d and
|
|
2420
|
|
- ;; recompute the result via d2exp. For backwards
|
|
2421
|
|
- ;; compatibility, drop the leading 0 when k <= 0 to
|
|
2422
|
|
- ;; maximize d, the number of digits shown.
|
|
2423
|
|
- (let* ((d-fit (compute-d-for-width w e k actual-exp is-negative-p at-sign-p))
|
|
2424
|
|
- (drop-zero-p (and d-fit (<= k 0))))
|
|
2425
|
|
- #+nil
|
|
2426
|
|
- (format t "d-fit = ~A, drop = ~A~%" d-fit drop-zero-p)
|
|
2427
|
|
- (if d-fit
|
|
2428
|
|
- (multiple-value-bind (mantissa exponent)
|
|
2429
|
|
- (parsed-exp-form (d2exp abs-value (d2exp-precision d-fit k)))
|
|
2430
|
|
- (format-e-string mantissa exponent is-negative-p
|
|
2431
|
|
- w e k overflowchar padchar exponentchar at-sign-p
|
|
2432
|
|
- drop-zero-p))
|
|
2433
|
|
- ;; Even with d = 0, the result won't fit. Let
|
|
2434
|
|
- ;; FORMAT-E-STRING overflow with the overflow
|
|
2435
|
|
- ;; character.
|
|
2436
|
|
- (format-e-string mantissa exponent is-negative-p
|
|
2437
|
|
- w e k overflowchar padchar exponentchar at-sign-p
|
|
2438
|
|
- nil)))))))))))
|
|
2439
|
|
-
|
|
2440
|
2262
|
(defun format-e (value w d e k overflowchar padchar exponentchar at-sign-p)
|
|
2441
|
2263
|
(declare (double-float value)
|
|
2442
|
2264
|
(fixnum k)
|
| ... |
... |
@@ -2478,23 +2300,6 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2478
|
2300
|
nil))))))))))))
|
|
2479
|
2301
|
|
|
2480
|
2302
|
;;; Ryu ~F
|
|
2481
|
|
-#+nil
|
|
2482
|
|
-(defun format-f-fixed (stream abs-value is-negative-p w d overflowchar padchar at-sign-p)
|
|
2483
|
|
- (let* ((raw-string (let ((f (d2fixed abs-value d)))
|
|
2484
|
|
- ;; If precision = 0, d2fixed doesn't have a
|
|
2485
|
|
- ;; dot. We need it.
|
|
2486
|
|
- (if (zerop d)
|
|
2487
|
|
- (concatenate 'string f ".")
|
|
2488
|
|
- f)))
|
|
2489
|
|
- (field
|
|
2490
|
|
- (with-output-to-string (s)
|
|
2491
|
|
- (cond (is-negative-p
|
|
2492
|
|
- (write-char #\- s))
|
|
2493
|
|
- (at-sign-p
|
|
2494
|
|
- (write-char #\+ s)))
|
|
2495
|
|
- (write-string raw-string s))))
|
|
2496
|
|
- (format-f-pad-overflow field w overflowchar padchar)))
|
|
2497
|
|
-
|
|
2498
|
2303
|
(declaim (inline pad-overflow))
|
|
2499
|
2304
|
(defun pad-overflow (stream field-len w overflowchar padchar field-writer)
|
|
2500
|
2305
|
"Apply width/pad/overflow rules. FIELD-WRITER is a thunk of zero
|
| ... |
... |
@@ -2565,34 +2370,6 @@ radix-R. If you have a power-list then pass it in as PL." |
|
2565
|
2370
|
(declare (dynamic-extent #'write-field))
|
|
2566
|
2371
|
(pad-overflow stream field-len w overflowchar padchar #'write-field))))
|
|
2567
|
2372
|
|
|
2568
|
|
-#+nil
|
|
2569
|
|
-(defun format-f-free (abs-value is-negative-p w overflowchar padchar at-sign-p)
|
|
2570
|
|
- ;; We need to call d2s to get the shortest.
|
|
2571
|
|
- (multiple-value-bind (mantissa exponent)
|
|
2572
|
|
- (parsed-exp-form (d2s abs-value))
|
|
2573
|
|
- (let* ((has-dot (find #\. mantissa))
|
|
2574
|
|
- (digit-count (if has-dot (1- (length mantissa)) (length mantissa)))
|
|
2575
|
|
- (int-len (max 1 (1+ exponent)))
|
|
2576
|
|
- (shortest-d (max 0 (- digit-count 1 exponent)))
|
|
2577
|
|
- (sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
2578
|
|
- (d-fit (and w (- w sign-len int-len 1))))
|
|
2579
|
|
- (cond
|
|
2580
|
|
- ((or (null w)
|
|
2581
|
|
- (>= d-fit shortest-d))
|
|
2582
|
|
- ;; Shortest fits or no width bound
|
|
2583
|
|
- (emit-shortest mantissa exponent is-negative-p w overflowchar padchar at-sign-p))
|
|
2584
|
|
- ((minusp d-fit)
|
|
2585
|
|
- ;; Integer part alone exceeds w--overflow path
|
|
2586
|
|
- (if overflowchar
|
|
2587
|
|
- (make-string w :initial-element overflowchar)
|
|
2588
|
|
- ;; No overflow; emit shortest at natural width, overflow w.
|
|
2589
|
|
- (emit-shortest mantissa exponent is-negative-p
|
|
2590
|
|
- w overflowchar padchar at-sign-p)))
|
|
2591
|
|
- (t
|
|
2592
|
|
- ;; d-fit between 0 and shortest-d. Shrink via d2fixed.
|
|
2593
|
|
- (format-f-fixed abs-value is-negative-p
|
|
2594
|
|
- w d-fit overflowchar padchar at-sign-p))))))
|
|
2595
|
|
-
|
|
2596
|
2373
|
(defun format-f-free (stream abs-value is-negative-p w
|
|
2597
|
2374
|
overflowchar padchar at-sign-p)
|
|
2598
|
2375
|
(multiple-value-bind (mantissa exponent)
|