[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: file i/o of binary data



  Date:	Wed, 29 Jan 1992 11:31:15 -0800
  From:	serafini@nas.nasa.gov (David B. Serafini)

  I'd like to be able to do i/o (read and write) on a file containing
  binary (not text) data, specifically, integers and single and double
  precision floats.

We've written the following code which reads and writes IEEE
single-precision floating point numbers.  It is portable, provided
that your Common Lisp implementation uses this representation for the
type single-float.  It should be a simple matter to code something
similar for doubles.  Note that this may not work for all IEEE values
(e.g. denormalized, infinities, etc.).

Franz folks: is there some (non-portable) way to construct
floating-point numbers given the bytes that compose them?

#-ieee-floating-point
(warn "non-IEEE floating point.  SINGLE-FLOAT i/o may not work.")

(defun single-float-write (single-float stream)
;;; Write SINGLE-FLOAT on STREAM in IEEE single-precision float format
  (declare (type single-float single-float))
  (multiple-value-bind (signif expon sign)
      (integer-decode-float
       ;; in Lucid all floats are IEEE double-precision
       #+lucid (lcl:round-to-single-precision single-float)
       #-lucid single-float)

    (declare (type (unsigned-byte 24) signif)
	     (type (signed-byte 8) expon)
	     (type (signed-byte 1) sign))

    (when (< signif (expt 2 23))
      (setq expon (- (+ 127 23))))

    (byte16-write
     (logior (the (unsigned-byte 16) (ash (if (minusp sign) 1 0) 15))
	     (the (unsigned-byte 15) (ash (the byte8 (+ expon 127 23)) 7))
	     (ldb (byte 7 16) signif))
     stream)
    (byte16-write (ldb (byte 16 0) signif) stream)))

(defun single-float-read (stream)
;;; read an IEEE single-precision float from STREAM
  (let* ((hi-16 (byte16-read stream))
	 (sign (ldb (byte 1 15) hi-16))
	 (exponent (ldb (byte 8 7) hi-16))
	 (lo-16 (byte16-read stream))
	 (signif (logior (if (= exponent 0) 0 (ash 1 23))
			 (the (unsigned-byte 23)
			      (ash (ldb (byte 7 0) hi-16) 16))
			 lo-16))
	 (float (if (zerop exponent)
		    (if (zerop signif)
			0.0
			(scale-float (float signif) (- exponent 126 23)))
		    (scale-float (float signif) (- exponent 127 23)))))
    (declare (type (unsigned-byte 16) hi-16 lo-16)
	     (type (unsigned-byte 24) signif)
	     (type (signed-byte 8) exponent)
	     (type (unsigned-byte 1) sign)
	     (type single-float float))
    (if (zerop sign) float (- float))))

(defun byte16-write (byte16 stream)
;;; Writes a BYTE16 on STREAM for reading by BYTE16-READ
  (declare (type (unsigned-byte 16) byte16)
	   (optimize (speed 3) (safety 0)))
  (write-byte (ldb (byte 8 8) byte16) stream)
  (write-byte (ldb (byte 8 0) byte16) stream))

(defun byte16-read (stream)
;;; reads & returns a byte16 from STREAM as written by BYTE16-WRITE
  (declare (optimize (speed 3) (safety 0)))
  (the (unsigned-byte 16)
       (logior (the (unsigned-byte 16) (ash (read-byte stream) 8))
	       (read-byte stream))))