1 ;; encode-decode-float.lisp
2 ;; Copyright 2007 by Robert Dodier
4 ;; This program is free software; you can redistribute it and/or
5 ;; modify it under the terms of the GNU General Public License.
7 ;; This program has NO WARRANTY, not even the implied warranty of
8 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 ;; These functions encode integers into 64 bit IEEE 754 floats
11 ;; and decode 64 bit floats into 64 bit integers.
12 ;; These functions cannot handle any other size of float.
14 ;; Encode float-64 to integer: SMASH-FLOAT-64-INTO-INTEGER
15 ;; Decode integer to float-64: CONSTRUCT-FLOAT-64-FROM-INTEGER
17 ;; Write float-64 to output stream: WRITE-FLOAT-64
18 ;; Read float-64 from input stream: READ-FLOAT-64
19 ;; Read an unsigned integer (of any size) from input stream: READ-UNSIGNED-INTEGER
20 ;; Write an unsigned integer (of any size) to output stream: WRITE-UNSIGNED-INTEGER
21 ;; Set assumed external byte order for input and output: DEFINE-EXTERNAL-BYTE-ORDER
25 (defun smash-float-into-integer (x)
27 (significand exponent sign
)
28 (integer-decode-float x
)
29 ;; This logic cannot be guaranteed to work -- there is no necessary
30 ;; correlation between IEEE 754 and CL floats. Oh well.
31 (if (or (typep x
'double-float
) (typep x
'long-float
))
32 (smash-decoded-float-64-into-integer significand exponent sign
)
33 (smash-decoded-float-32-into-integer significand exponent sign
))))
35 (defun smash-decoded-float-32-into-integer (significand exponent sign
)
48 (defun construct-float-32-from-integer (x)
50 (significand exponent sign
)
51 (extract-smashed-float-32-from-integer x
)
52 (* sign
(scale-float (float significand
1f0
) exponent
))))
54 (defun extract-smashed-float-32-from-integer (x)
58 ((significand (dpb x
(byte 23 0) #x800000
))
59 (exponent (- (ldb (byte 8 23) x
) 127 23))
60 (sign (if (eql (ldb (byte 1 31) x
) 0) 1 -
1)))
61 (values significand exponent sign
))))
63 (defun smash-decoded-float-64-into-integer (significand exponent sign
)
76 (defun construct-float-64-from-integer (x)
78 (significand exponent sign
)
79 (extract-smashed-float-64-from-integer x
)
80 (* sign
(scale-float (float significand
1d0
) exponent
))))
82 (defun extract-smashed-float-64-from-integer (x)
86 ((significand (dpb x
(byte 52 0) #x10000000000000
))
87 (exponent (- (ldb (byte 11 52) x
) 1023 52))
88 (sign (if (eql (ldb (byte 1 63) x
) 0) 1 -
1)))
89 (values significand exponent sign
))))
91 ;; Stream input and output
93 (defun write-float (x s
)
94 (write-unsigned-integer (smash-float-into-integer x
) (size-in-bytes x
) s
))
96 (defun size-in-bytes (x)
97 (if (or (typep x
'double-float
) (typep x
'long-float
)) 8 4)) ;; AUGHHHH!! THIS IS TERRIBLE!
99 (defun read-float-64 (s)
100 (let ((x (read-unsigned-integer 8 s
)))
101 (if (eq x
'eof
) 'eof
(construct-float-64-from-integer x
))))
103 ;; READ-UNSIGNED-INTEGER, WRITE-UNSIGNED-INTEGER, and associated
104 ;; byte order stuff adapted from read-bytes-standalone.lisp,
105 ;; by Martin Raspaud and Robert Strandh,
106 ;; which was released under terms of GNU GPL v2 or later.
108 (deftype external-byte-order
()
109 "Defines the legal values for *EXTERNAL-BYTE-ORDER*."
112 (defvar *external-byte-order
* :msb
113 "*EXTERNAL-BYTE-ORDER* must be either :msb or :lsb")
115 (defun define-external-byte-order (x)
116 (check-type x external-byte-order
)
117 (setf *external-byte-order
* x
))
119 (defun read-unsigned-integer (nb-bytes s
)
120 "Read an unsigned integer of size NB-BYTES bytes from input stream S."
121 (if (zerop nb-bytes
) 0
123 (dotimes (i nb-bytes
)
124 (let ((x (read-byte s nil
'eof
)))
126 (return-from read-unsigned-integer
'eof
)
127 (setq bytes
(nconc bytes
(list x
))))))
128 (case *external-byte-order
*
130 (mapc #'(lambda (x) (setq y
(+ x
(ash y
8)))) (nreverse bytes
)))
132 (mapc #'(lambda (x) (setq y
(+ x
(ash y
8)))) bytes
)))
135 (defun write-unsigned-integer (quantity nb-bytes s
)
136 "Write an unsigned integer of size NB-BYTES bytes to output stream S."
137 (case *external-byte-order
*
139 (unless (zerop nb-bytes
)
140 (write-byte (logand quantity
#xff
) s
)
141 (write-unsigned-integer
146 (unless (zerop nb-bytes
)
147 (write-unsigned-integer
151 (write-byte (logand quantity
#xff
) s
)))))