| ... |
... |
@@ -23,10 +23,6 @@ |
|
23
|
23
|
|
|
24
|
24
|
;;;; C-style hex float printer and parser
|
|
25
|
25
|
|
|
26
|
|
-;;; FLOAT-TO-HEX-STRING -- Public
|
|
27
|
|
-;;;
|
|
28
|
|
-;;; Return a string representing a single and double-floats in C-style
|
|
29
|
|
-;;; hex format.
|
|
30
|
26
|
(defun trim-trailing-zeros (s)
|
|
31
|
27
|
"Remove trailing zero characters from string S, preserving internal zeros."
|
|
32
|
28
|
(let ((last-nonzero (position #\0 s :test #'char/= :from-end t)))
|
| ... |
... |
@@ -35,70 +31,65 @@ |
|
35
|
31
|
"")))
|
|
36
|
32
|
|
|
37
|
33
|
|
|
38
|
|
-(defun write-hex-float-double (x stream mantissa-bits type)
|
|
39
|
|
- "Print a single- or double-float in hex format onto STREAM.
|
|
40
|
|
- MANTISSA-BITS is 23 for single, 52 for double (excluding implicit leading 1).
|
|
41
|
|
- X must be the original float of the appropriate type; do not pre-coerce."
|
|
42
|
|
- (when (and (not (float-nan-p x)) (minusp (float-sign x)))
|
|
43
|
|
- (write-char #\- stream))
|
|
44
|
|
- (let ((x (abs x)))
|
|
45
|
|
- (cond
|
|
46
|
|
- ((float-nan-p x)
|
|
47
|
|
- (write-string "0x0.0p+nan" stream)
|
|
48
|
|
- (ecase type
|
|
49
|
|
- (:single (write-char #\f stream))
|
|
50
|
|
- (:double (values))))
|
|
|
34
|
+(defun write-hex-float-double (x stream)
|
|
|
35
|
+ "Print a single-float or double-float in hex format onto STREAM."
|
|
|
36
|
+ ;; Float type and mantissa width are derived from the type of X.
|
|
|
37
|
+ (multiple-value-bind (mantissa-bits suffix-char min-c-exp)
|
|
|
38
|
+ (etypecase x
|
|
|
39
|
+ (single-float (values 23 #\f -126))
|
|
|
40
|
+ (double-float (values 52 nil -1022)))
|
|
|
41
|
+ (when (and (not (float-nan-p x)) (minusp (float-sign x)))
|
|
|
42
|
+ (write-char #\- stream))
|
|
|
43
|
+ (let ((x (abs x)))
|
|
|
44
|
+ (cond
|
|
|
45
|
+ ((float-nan-p x)
|
|
|
46
|
+ (write-string "0x0.0p+nan" stream)
|
|
|
47
|
+ (when suffix-char (write-char suffix-char stream)))
|
|
51
|
48
|
|
|
52
|
|
- ((float-infinity-p x)
|
|
53
|
|
- (write-string "0x1.0p+inf" stream)
|
|
54
|
|
- (ecase type
|
|
55
|
|
- (:single (write-char #\f stream))
|
|
56
|
|
- (:double (values))))
|
|
|
49
|
+ ((float-infinity-p x)
|
|
|
50
|
+ (write-string "0x1.0p+inf" stream)
|
|
|
51
|
+ (when suffix-char (write-char suffix-char stream)))
|
|
57
|
52
|
|
|
58
|
|
- ((zerop x)
|
|
59
|
|
- (write-string "0x0p+0" stream)
|
|
60
|
|
- (ecase type
|
|
61
|
|
- (:single (write-char #\f stream))
|
|
62
|
|
- (:double (values))))
|
|
|
53
|
+ ((zerop x)
|
|
|
54
|
+ (write-string "0x0p+0" stream)
|
|
|
55
|
+ (when suffix-char (write-char suffix-char stream)))
|
|
63
|
56
|
|
|
64
|
|
- (t
|
|
65
|
|
- (multiple-value-bind (significand exponent sign)
|
|
66
|
|
- (integer-decode-float x)
|
|
67
|
|
- (declare (ignore sign))
|
|
68
|
|
- (let* ((c-exp (+ exponent mantissa-bits))
|
|
69
|
|
- (min-c-exp (ecase type
|
|
70
|
|
- (:double -1022)
|
|
71
|
|
- (:single -126)))
|
|
72
|
|
- (denormalp (< c-exp min-c-exp))
|
|
73
|
|
- (hex-digits (ceiling mantissa-bits 4))
|
|
74
|
|
- (frac-shift (- (* 4 hex-digits) mantissa-bits))
|
|
75
|
|
- (frac (if denormalp
|
|
76
|
|
- (ash significand
|
|
77
|
|
- (+ (- c-exp min-c-exp) frac-shift))
|
|
78
|
|
- (ash (logand significand
|
|
79
|
|
- (1- (ash 1 mantissa-bits)))
|
|
80
|
|
- frac-shift)))
|
|
81
|
|
- (out-exp (if denormalp min-c-exp c-exp))
|
|
82
|
|
- (frac-str (trim-trailing-zeros
|
|
83
|
|
- (format nil "~v,'0X" hex-digits frac))))
|
|
84
|
|
- (write-string "0x" stream)
|
|
85
|
|
- (write-char (if denormalp #\0 #\1) stream)
|
|
86
|
|
- (unless (zerop (length frac-str))
|
|
87
|
|
- (write-char #\. stream)
|
|
88
|
|
- (write-string frac-str stream))
|
|
89
|
|
- (write-char #\p stream)
|
|
90
|
|
- (when (>= out-exp 0) (write-char #\+ stream))
|
|
91
|
|
- (write-string (format nil "~D" out-exp) stream)
|
|
92
|
|
- (ecase type
|
|
93
|
|
- (:single (write-char #\f stream))
|
|
94
|
|
- (:double (values))))))))
|
|
95
|
|
- (values))
|
|
|
57
|
+ (t
|
|
|
58
|
+ (multiple-value-bind (significand exponent sign)
|
|
|
59
|
+ (integer-decode-float x)
|
|
|
60
|
+ (declare (ignore sign))
|
|
|
61
|
+ (let* ((c-exp (+ exponent mantissa-bits))
|
|
|
62
|
+ (denormalp (< c-exp min-c-exp))
|
|
|
63
|
+ (hex-digits (ceiling mantissa-bits 4))
|
|
|
64
|
+ (frac-shift (- (* 4 hex-digits) mantissa-bits))
|
|
|
65
|
+ (frac (if denormalp
|
|
|
66
|
+ (ash significand
|
|
|
67
|
+ (+ (- c-exp min-c-exp) frac-shift))
|
|
|
68
|
+ (ash (logand significand
|
|
|
69
|
+ (1- (ash 1 mantissa-bits)))
|
|
|
70
|
+ frac-shift)))
|
|
|
71
|
+ (out-exp (if denormalp min-c-exp c-exp))
|
|
|
72
|
+ (frac-str (trim-trailing-zeros
|
|
|
73
|
+ (format nil "~v,'0X" hex-digits frac))))
|
|
|
74
|
+ (write-string "0x" stream)
|
|
|
75
|
+ (write-char (if denormalp #\0 #\1) stream)
|
|
|
76
|
+ (unless (zerop (length frac-str))
|
|
|
77
|
+ (write-char #\. stream)
|
|
|
78
|
+ (write-string frac-str stream))
|
|
|
79
|
+ (write-char #\p stream)
|
|
|
80
|
+ (when (>= out-exp 0)
|
|
|
81
|
+ (write-char #\+ stream))
|
|
|
82
|
+ (write-string (format nil "~D" out-exp) stream)
|
|
|
83
|
+ (when suffix-char
|
|
|
84
|
+ (write-char suffix-char stream)))))))
|
|
|
85
|
+ (values)))
|
|
96
|
86
|
|
|
97
|
87
|
|
|
|
88
|
+#+double-double
|
|
98
|
89
|
(defun write-hex-float-double-double (x stream)
|
|
99
|
|
- "Print a double-double-float in hex format onto STREAM.
|
|
100
|
|
- Reconstructs the full significand from hi and lo components
|
|
101
|
|
- using exact integer arithmetic before formatting."
|
|
|
90
|
+ "Print a double-double-float in hex format onto STREAM."
|
|
|
91
|
+ ;; Reconstructs the full significand from hi and lo components using
|
|
|
92
|
+ ;; exact integer arithmetic before formatting."
|
|
102
|
93
|
(let* ((hi (kernel:double-double-hi x))
|
|
103
|
94
|
(lo (kernel:double-double-lo x))
|
|
104
|
95
|
(hi (abs hi)))
|
| ... |
... |
@@ -125,7 +116,8 @@ |
|
125
|
116
|
(denormalp (< c-exp min-c-exp))
|
|
126
|
117
|
(raw-frac-bits (if (zerop lo)
|
|
127
|
118
|
52
|
|
128
|
|
- (+ (- exp-hi exp-lo) 52)))
|
|
|
119
|
+ (+ (- exp-hi exp-lo)
|
|
|
120
|
+ 52)))
|
|
129
|
121
|
(frac-bits (* 4 (ceiling raw-frac-bits 4)))
|
|
130
|
122
|
(hex-digits (/ frac-bits 4))
|
|
131
|
123
|
(shift (if denormalp
|
| ... |
... |
@@ -145,25 +137,16 @@ |
|
145
|
137
|
(write-char #\. stream)
|
|
146
|
138
|
(write-string frac-str stream))
|
|
147
|
139
|
(write-char #\p stream)
|
|
148
|
|
- (when (>= out-exp 0) (write-char #\+ stream))
|
|
|
140
|
+ (when (>= out-exp 0)
|
|
|
141
|
+ (write-char #\+ stream))
|
|
149
|
142
|
(write-string (format nil "~D" out-exp) stream)
|
|
150
|
143
|
(write-char #\w stream))))))
|
|
151
|
144
|
(values)))
|
|
152
|
145
|
|
|
153
|
|
-(defun write-hex-float (x &optional (stream *standard-output*))
|
|
154
|
|
- "Write float X to STREAM in C-style hex format.
|
|
155
|
|
- STREAM defaults to *standard-output*.
|
|
156
|
|
- single-float => 0x<mantissa>p<exp>f
|
|
157
|
|
- double-float => 0x<mantissa>p<exp>
|
|
158
|
|
- double-double-float => 0x<mantissa>p<exp>w
|
|
159
|
|
- Negative zero is printed with a leading minus sign."
|
|
160
|
|
- (let ((*print-case* :downcase))
|
|
161
|
|
- (etypecase x
|
|
162
|
|
- (double-double-float (write-hex-float-double-double x stream))
|
|
163
|
|
- (double-float (write-hex-float-double x stream 52 :double))
|
|
164
|
|
- (single-float (write-hex-float-double x stream 23 :single))))
|
|
165
|
|
- (values))
|
|
166
|
|
-
|
|
|
146
|
+;;; FLOAT-TO-HEX-STRING -- Public
|
|
|
147
|
+;;;
|
|
|
148
|
+;;; Return a string representing a single and double-floats in C-style
|
|
|
149
|
+;;; hex format.
|
|
167
|
150
|
(defun float-to-hex-string (x)
|
|
168
|
151
|
"Return a string containing the C-style hex float representation of X.
|
|
169
|
152
|
single-float => \"0x<mantissa>p<exp>f\"
|
| ... |
... |
@@ -173,6 +156,30 @@ |
|
173
|
156
|
(write-hex-float x s)))
|
|
174
|
157
|
|
|
175
|
158
|
|
|
|
159
|
+;;; WRITE-HEX-FLOAT -- Public
|
|
|
160
|
+;;;
|
|
|
161
|
+;;; Writes a float value (single, double, or double-double) in hex
|
|
|
162
|
+;;; format to a stream, defaulting to *standard-output*.
|
|
|
163
|
+(defun write-hex-float (x &optional (stream *standard-output*))
|
|
|
164
|
+ "Write float X to STREAM in C-style hex format. STREAM defaults to *standard-output*.
|
|
|
165
|
+
|
|
|
166
|
+ single-float => 0x<mantissa>p<exp>f
|
|
|
167
|
+ double-float => 0x<mantissa>p<exp>
|
|
|
168
|
+ double-double-float => 0x<mantissa>p<exp>w
|
|
|
169
|
+
|
|
|
170
|
+ Negative zero is printed with a leading minus sign."
|
|
|
171
|
+ (let ((*print-case* :downcase))
|
|
|
172
|
+ (etypecase x
|
|
|
173
|
+ (single-float
|
|
|
174
|
+ (write-hex-float-double x stream))
|
|
|
175
|
+ (double-float
|
|
|
176
|
+ (write-hex-float-double x stream))
|
|
|
177
|
+ #+double-double
|
|
|
178
|
+ (double-double-float
|
|
|
179
|
+ (write-hex-float-double-double x stream))))
|
|
|
180
|
+ (values))
|
|
|
181
|
+
|
|
|
182
|
+
|
|
176
|
183
|
;;; FORMAT-HEX-FLOAT -- Public
|
|
177
|
184
|
;;;
|
|
178
|
185
|
;;; Function that can be used in a FORMAT ~/
|
| ... |
... |
@@ -180,18 +187,15 @@ |
|
180
|
187
|
"Format function for use with ~/package:format-hex-float/.
|
|
181
|
188
|
Ignores colon modifier.
|
|
182
|
189
|
At-sign modifier forces a leading + sign on non-negative values.
|
|
183
|
|
- Example: (format t \"~@/format-hex-float/\" 3.0d0) => +0x1.8p+1"
|
|
|
190
|
+ Example: (format t \"~@/ext:format-hex-float/\" 3.0d0) => +0x1.8p+1"
|
|
184
|
191
|
(declare (ignore colonp args))
|
|
185
|
192
|
(when (and atsignp
|
|
186
|
|
- (not (float-nan-p (if (typep x 'ext:double-double-float)
|
|
187
|
|
- (kernel:double-double-hi x)
|
|
188
|
|
- x)))
|
|
189
|
|
- (not (minusp (float-sign (if (typep x 'ext:double-double-float)
|
|
190
|
|
- (kernel:double-double-hi x)
|
|
191
|
|
- x)))))
|
|
|
193
|
+ (not (float-nan-p x))
|
|
|
194
|
+ (not (minusp (float-sign x))))
|
|
192
|
195
|
(write-char #\+ stream))
|
|
193
|
196
|
(write-hex-float x stream))
|
|
194
|
197
|
|
|
|
198
|
+
|
|
195
|
199
|
(define-condition hex-parse-error (parse-error)
|
|
196
|
200
|
((text :initarg :text :reader hex-parse-error-text)
|
|
197
|
201
|
(message :initarg :message :reader hex-parse-error-message))
|