Re: Converting bits to FLOAT



Denis Bueno <gtg385h@xxxxxxxxxxxxxxx> writes:

> I'm parsing TIFF images in Lisp, and some of the bitfields in the image can
> (possibly) contain floats, packed in IEEE format. I've written functions that
> convert from other datatypes to the Lisp native format (shorts, longs,
> rationals, etc.), but can't figure out what to do for floats.
>
> Is there a way to convert a bunch of bits (say, a 4-byte unsigned int) into a
> FLOAT object? I see that DECODE-FLOAT allows one to go the other way....

It depends on the floating point representation. Here's some code I
wrote to deal with the two IEEE floating-point formats (one 4-bytes
and the other 8-bytes) used in Java class files. It also handles
not-a-number and positive-and-negative infinities, at the moment by
returning a symbol. In implementations that support those constructs
directly you might want to return the appropriate object. This code is
licensed under a BSD-style license so you're free to use it how you
wish. (I'm pretty sure it was in a clean working state last time I
touched it but there's no guarantees that there aren't horrendous bugs
in it.)

(defun encode-float-bits (float sign-byte exponent-byte mantissa-byte bias)
(multiple-value-bind (original-mantissa original-exponent sign) (integer-decode-float (float float 0d0))
(multiple-value-bind (mantissa exponent) (scale original-mantissa original-exponent (1+ (byte-size mantissa-byte)))
(incf exponent (byte-size mantissa-byte))
(when (zerop mantissa)
(setf exponent (- bias)))
(when (<= exponent (- bias))
(setf (values mantissa exponent) (denormalize original-mantissa original-exponent bias mantissa-byte)))
(incf exponent bias)
(when (> (integer-length exponent) (byte-size exponent-byte))
(setf mantissa 0 exponent (ldb (byte (byte-size exponent-byte) 0) (lognot 0))))
(let ((result 0))
(setf (ldb sign-byte result) (if (plusp sign) 0 1))
(setf (ldb exponent-byte result) exponent)
(setf (ldb mantissa-byte result) mantissa)
result))))

(defun decode-float-bits (bits sign-byte exponent-byte mantissa-byte bias)
(let ((sign (if (zerop (ldb sign-byte bits)) 1 -1))
(exponent (ldb exponent-byte bits))
(mantissa (ldb mantissa-byte bits)))
(if (= (logcount (ldb exponent-byte bits)) (byte-size exponent-byte))
(if (zerop mantissa)
(if (plusp sign) 'positive-infinity 'negative-infinity)
'not-a-number)
(progn
(when (plusp exponent)
(incf mantissa (expt 2 (byte-size mantissa-byte))))
(if (zerop exponent)
(setf exponent (- 1 bias (byte-size mantissa-byte)))
(setf exponent (- (- exponent (byte-size mantissa-byte)) bias)))
(float (* sign (* mantissa (expt 2 exponent))) 0d0)))))

(defun scale-integer (value bits)
"Scale an integer value so it fits in the given number of bits."
(if (zerop value)
(values 0 0)
(let ((scale (- bits (integer-length value))))
(values (round (* value (expt 2 scale))) scale))))

(defun scale (mantissa exponent mantissa-bits)
"Scale an integer value so it fits in the given number of bits."
(multiple-value-bind (mantissa scale) (scale-integer mantissa mantissa-bits)
(values mantissa (- exponent scale))))

(defun denormalize (mantissa exponent bias mantissa-byte)
(multiple-value-bind (mantissa exponent) (scale mantissa exponent (byte-size mantissa-byte))
(incf exponent (byte-size mantissa-byte))
(values (ash mantissa (- exponent (1+ (- bias)))) (- bias))))

(defun encode-single-float-bits (float)
(encode-float-bits float (byte 1 31) (byte 8 23) (byte 23 0) 127))

(defun encode-double-float-bits (float)
(encode-float-bits float (byte 1 63) (byte 11 52) (byte 52 0) 1023))

(defun decode-single-float-bits (bits)
(decode-float-bits bits (byte 1 31) (byte 8 23) (byte 23 0) 127))

(defun decode-double-float-bits (bits)
(decode-float-bits bits (byte 1 63) (byte 11 52) (byte 52 0) 1023))

-Peter

--
Peter Seibel * peter@xxxxxxxxxxxxxxx
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/
.



Relevant Pages

  • Re: sound synthesis
    ... > the declarations and using short float helped, ... (defun mix (target-samples source-samples start sample-rate) ... (declare (float sample-rate seconds) ... (defun fm-gong (time freq) ...
    (comp.lang.lisp)
  • Re: how do I get more numbers past the decimal?
    ... A floating point number is stored on a 32 bit machine using the 24 bit for the mantissa and its sign and 8 bits for the exponent and its sign. ... A float value can be exactly represented by up to 9 decimal digits. ...
    (comp.lang.php)
  • Re: Unknown floating point representation
    ... float should be. ... Also, the exponent is at the LSB end of the number, after the mantissa ... int exponent = (in & expBits); ...
    (comp.lang.java.programmer)
  • Re: Unknown floating point representation
    ... float should be. ... Also, the exponent is at the LSB end of the number, after the mantissa ... Number of places to shift the decimal point. ... means 6 decimal digits after the decimal point. ...
    (comp.lang.java.programmer)
  • Re: Unknown floating point representation
    ... float should be. ... Also, the exponent is at the LSB end of the number, after the mantissa ... int exponent = (in & expBits); ...
    (comp.lang.java.programmer)