| ... |
... |
@@ -38,7 +38,9 @@ |
|
38
|
38
|
"Buffer size for d2fixed.")
|
|
39
|
39
|
|
|
40
|
40
|
(defun d2fixed (d precision)
|
|
41
|
|
- "Lisp interface to Ryu d2fixed routine (specically d2fixed_buffered)"
|
|
|
41
|
+ "Lisp interface to Ryu d2fixed routine (specically d2fixed_buffered).
|
|
|
42
|
+ D is the number to convert and PRECISION is the number of digits
|
|
|
43
|
+ after the decimal point. The total number of digits could be more."
|
|
42
|
44
|
(declare (double-float d)
|
|
43
|
45
|
(type (integer 0 #.+d2fixed-max-precision+) precision))
|
|
44
|
46
|
(alien:with-alien ((buf (alien:array c-call:char #.+d2fixed-buffer-size+)))
|
| ... |
... |
@@ -54,7 +56,9 @@ |
|
54
|
56
|
(alien:cast buf c-call:c-string)))
|
|
55
|
57
|
|
|
56
|
58
|
(defun d2exp (d precision)
|
|
57
|
|
- "Lisp interface to Ryu d2exp (specifically d2exp-buffered)."
|
|
|
59
|
+ "Lisp interface to Ryu d2exp (specifically d2exp-buffered). D is the
|
|
|
60
|
+ number to convert and PRECISION is the number of digits after the
|
|
|
61
|
+ decimal point. The result is of the form \"d.ddddEeee\"."
|
|
58
|
62
|
(declare (double-float d)
|
|
59
|
63
|
(type (integer 0 #.+d2fixed-max-precision+) precision))
|
|
60
|
64
|
(alien:with-alien ((buf (alien:array c-call:char #.+d2fixed-buffer-size+)))
|
| ... |
... |
@@ -70,7 +74,9 @@ |
|
70
|
74
|
(alien:cast buf c-call:c-string)))
|
|
71
|
75
|
|
|
72
|
76
|
(defun d2s (d)
|
|
73
|
|
- "Lisp interface to Ryu d2s (specifically d2s_buffered"
|
|
|
77
|
+ "Lisp interface to Ryu d2s (specifically d2s_buffered. D is the number
|
|
|
78
|
+ to convert and the result is the shortest string that reproduces the
|
|
|
79
|
+ value when read back in."
|
|
74
|
80
|
(declare (double-float d))
|
|
75
|
81
|
(alien:with-alien ((buf (alien:array c-call:char #.+d2fixed-buffer-size+)))
|
|
76
|
82
|
(alien:alien-funcall
|
| ... |
... |
@@ -83,6 +89,9 @@ |
|
83
|
89
|
(alien:cast buf c-call:c-string)))
|
|
84
|
90
|
|
|
85
|
91
|
(defun f2s (s)
|
|
|
92
|
+ "Lisp interface to Ryu f2s (specifically f2s_buffered. D is the number
|
|
|
93
|
+ to convert and the result is the shortest string that reproduces the
|
|
|
94
|
+ value when read back in."
|
|
86
|
95
|
(declare (single-float s))
|
|
87
|
96
|
(alien:with-alien ((buf (alien:array c-call:char 16)))
|
|
88
|
97
|
(alien:alien-funcall
|
| ... |
... |
@@ -103,17 +112,14 @@ |
|
103
|
112
|
(double-float (d2s (abs f)))
|
|
104
|
113
|
(single-float (f2s (abs f)))))
|
|
105
|
114
|
|
|
106
|
|
-(defun parsed-d2exp (pos-x digits)
|
|
107
|
|
- (let* ((raw (d2exp pos-x digits))
|
|
108
|
|
- ;; Parse the result from d2exp. It has the form "d.dddEeee".
|
|
109
|
|
- (e-pos (position #\e raw))
|
|
110
|
|
- (mantissa (subseq raw 0 e-pos))
|
|
111
|
|
- (exp (parse-integer raw :start (1+ e-pos))))
|
|
112
|
|
- (values mantissa exp)))
|
|
113
|
|
-
|
|
114
|
115
|
(defun parsed-exp-form (raw-string)
|
|
|
116
|
+ "Parse RAW-STRING which is a number in exponential form and return the
|
|
|
117
|
+ mantissa part as a string and the exponent part as an integer.
|
|
|
118
|
+
|
|
|
119
|
+ RAW-STRING is of the form \"d.ddddEeee\" where the exponent marker
|
|
|
120
|
+ must exist and must be \"e\" or \"E\"."
|
|
115
|
121
|
;; Parse RAW-STRING, that is in exponential form. That is, it must
|
|
116
|
|
- ;; the form "d.dddEeee". There cannot be a leading sign.
|
|
|
122
|
+ ;; the form "d.dddEeee". There cannot be a leading sign. Returns
|
|
117
|
123
|
(let* ((e-pos (position-if #'(lambda (c)
|
|
118
|
124
|
(member c '(#\e #\E)))
|
|
119
|
125
|
raw-string))
|
| ... |
... |
@@ -133,12 +139,20 @@ |
|
133
|
139
|
(- (length mantissa)
|
|
134
|
140
|
(if (find #\. mantissa) 1 0)))
|
|
135
|
141
|
|
|
|
142
|
+(defun count-decimal-digits (n)
|
|
|
143
|
+ "Number of decimal digits in N. N is the absolute value of a
|
|
|
144
|
+ double-float's exponent, so 0 <= n <= 324."
|
|
|
145
|
+ (declare (type (integer 0 324) n))
|
|
|
146
|
+ (cond ((< n 10) 1)
|
|
|
147
|
+ ((< n 100) 2)
|
|
|
148
|
+ (t 3)))
|
|
|
149
|
+
|
|
136
|
150
|
(defun compute-d-for-width (w e k actual-exp is-negative-p at-sign-p)
|
|
137
|
|
- ;; Find the largest d (precision) value that fits in width W given
|
|
138
|
|
- ;; the actual exponent (adjusted by k), and whether signs are
|
|
139
|
|
- ;; printed or not.
|
|
140
|
|
- ;;
|
|
141
|
|
- ;; Returns NIL if no width d can fit in a field of length w.
|
|
|
151
|
+ "Find the largest d (precision) value that fits in width W given the
|
|
|
152
|
+ actual exponent (adjusted by k), and whether signs are printed or
|
|
|
153
|
+ not.
|
|
|
154
|
+
|
|
|
155
|
+ Returns NIL if no width d can fit in a field of length w."
|
|
142
|
156
|
(declare (fixnum k actual-exp))
|
|
143
|
157
|
(let* ((sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
144
|
158
|
(exp-digits (max (or e 1)
|
| ... |
... |
@@ -162,25 +176,16 @@ |
|
162
|
176
|
(t
|
|
163
|
177
|
d-fit))))
|
|
164
|
178
|
|
|
165
|
|
-(defun count-decimal-digits (n)
|
|
166
|
|
- "Number of decimal digits in N. N is the absolute value of a
|
|
167
|
|
- double-float's exponent, so 0 <= n <= 324."
|
|
168
|
|
- (declare (type (integer 0 324) n)
|
|
169
|
|
- (optimize speed))
|
|
170
|
|
- (cond ((< n 10) 1)
|
|
171
|
|
- ((< n 100) 2)
|
|
172
|
|
- (t 3)))
|
|
173
|
|
-
|
|
174
|
179
|
(defun compute-exp-output-length (mantissa actual-exp k e is-negative-p at-sign-p
|
|
175
|
180
|
drop-leading-zero-p)
|
|
|
181
|
+ "Compute length of the ~E result with the given parameters, but don't
|
|
|
182
|
+ build the string. MANTISSA is \"d[.dddd]\" from d2exp or
|
|
|
183
|
+ d2s. ACTUAL-EXP is the exponent with scaling factor applied. If
|
|
|
184
|
+ DROP-LEADING-ZERO-P is non-NIL, the leading \"0\" before the dot (in
|
|
|
185
|
+ the K <= 0 form) is omitted from the length."
|
|
176
|
186
|
(declare (type simple-string mantissa)
|
|
177
|
187
|
(fixnum actual-exp k)
|
|
178
|
188
|
(type (or null fixnum) e))
|
|
179
|
|
- ;; Compute length of the ~E result with the given parameters, but
|
|
180
|
|
- ;; don't build the string. MANTISSA is "d[.dddd]" from d2exp or d2s.
|
|
181
|
|
- ;; ACTUAL-EXP is the exponent with scaling factor applied. If
|
|
182
|
|
- ;; DROP-LEADING-ZERO-P is non-NIL, the leading "0" before the dot
|
|
183
|
|
- ;; (in the K <= 0 form) is omitted from the length.
|
|
184
|
189
|
(let* ((sign-len (if (or is-negative-p at-sign-p) 1 0))
|
|
185
|
190
|
(exp-digits (max (or e 1)
|
|
186
|
191
|
(count-decimal-digits (abs actual-exp))))
|
| ... |
... |
@@ -309,8 +314,8 @@ |
|
309
|
314
|
(abs (float value 1d0))))))
|
|
310
|
315
|
|
|
311
|
316
|
(defun d2exp-precision (d k)
|
|
312
|
|
- ;; Compute precision for d2exp when CL requests D digits and the
|
|
313
|
|
- ;; scale factor is K."
|
|
|
317
|
+ "Compute precision for d2exp when CL requests D digits and the
|
|
|
318
|
+ scale factor is K."
|
|
314
|
319
|
(cond ((plusp k)
|
|
315
|
320
|
;; k digits before the decimal, d-k+1 after, so D is the
|
|
316
|
321
|
;; right precision for d2exp.
|
| ... |
... |
@@ -326,6 +331,14 @@ |
|
326
|
331
|
(defun format-e-string (stream mantissa exponent is-negative-p w e k
|
|
327
|
332
|
overflowchar padchar exponentchar at-sign-p
|
|
328
|
333
|
drop-leading-zero-p)
|
|
|
334
|
+ "Write the ~E representation of MANTISSA * 10^EXPONENT to STREAM,
|
|
|
335
|
+ right-justified in a field of width W. If specified, the PADCHAR is
|
|
|
336
|
+ inserted. If OVERFLOWCHAR is given and the result won't fit in the
|
|
|
337
|
+ field, OVERFLOWCHAR replaces the result.
|
|
|
338
|
+
|
|
|
339
|
+ K is the scale factor causing the decimal point to be placed K
|
|
|
340
|
+ digits in from the start and the displayed exponent is adjusted
|
|
|
341
|
+ appropriately."
|
|
329
|
342
|
(declare (type simple-string mantissa)
|
|
330
|
343
|
(fixnum exponent k))
|
|
331
|
344
|
(let* ((shown-exp (- exponent (1- k)))
|
| ... |
... |
@@ -486,6 +499,8 @@ |
|
486
|
499
|
;;; Ryu ~F
|
|
487
|
500
|
(defun format-f-fixed (stream value w d
|
|
488
|
501
|
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."
|
|
489
|
504
|
(declare (type (or single-float double-float) value))
|
|
490
|
505
|
(multiple-value-bind (is-negative-p abs-value)
|
|
491
|
506
|
(get-sign-and-absolute-value value)
|
| ... |
... |
@@ -500,13 +515,15 @@ |
|
500
|
515
|
;; that case here and drop the zero if the field would not
|
|
501
|
516
|
;; otherwise fit in W. For exact zero the leading digit is
|
|
502
|
517
|
;; required, so PLUSP ABS-VALUE gates the dropping.
|
|
503
|
|
- (lpoint-droppable
|
|
|
518
|
+ (leading-zero-droppable
|
|
504
|
519
|
(and (plusp abs-value)
|
|
505
|
520
|
(>= raw-len 2)
|
|
506
|
521
|
(char= (char raw-string 0) #\0)
|
|
507
|
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.
|
|
508
|
525
|
(drop-leading-zero-p
|
|
509
|
|
- (and lpoint-droppable
|
|
|
526
|
+ (and leading-zero-droppable
|
|
510
|
527
|
w
|
|
511
|
528
|
(> full-field-len w)))
|
|
512
|
529
|
(field-len (if drop-leading-zero-p
|
| ... |
... |
@@ -595,13 +612,13 @@ |
|
595
|
612
|
;; The leading "0." may be shortened to "." when the magnitude
|
|
596
|
613
|
;; is < 1 (integer part is the single digit "0") and nonzero,
|
|
597
|
614
|
;; and only when the full field would not fit in W.
|
|
598
|
|
- (lpoint-droppable
|
|
|
615
|
+ (leading-zero-droppable
|
|
599
|
616
|
(and (= int-end 1)
|
|
600
|
617
|
(char= (char rounded 0) #\0)
|
|
601
|
618
|
(not (zerop value))))
|
|
602
|
619
|
(full-len (+ sign-len int-end 1 frac-out-len))
|
|
603
|
620
|
(drop-leading-zero-p
|
|
604
|
|
- (and lpoint-droppable w (> full-len w)))
|
|
|
621
|
+ (and leading-zero-droppable w (> full-len w)))
|
|
605
|
622
|
(field-len (if drop-leading-zero-p (1- full-len) full-len)))
|
|
606
|
623
|
(flet ((write-field ()
|
|
607
|
624
|
(cond (is-negative-p (write-char #\- stream))
|