From: Denis Bueno
Subject: Converting bits to FLOAT
Date: 
Message-ID: <gtg385h-74C2FC.13070602092005@news-int2.gatech.edu>
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....

-Denis

From: Wade Humeniuk
Subject: Re: Converting bits to FLOAT
Date: 
Message-ID: <R10Se.252948$on1.195537@clgrps13>
Denis Bueno wrote:
> 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....
> 

Here is a simplistic version,

I think the solution is just a straight up extraction of
bits and calculation,

(defun int32-to-float (integer)
   "Bit 31 is sign, bits 8 - 30 is mantissa, bits 0 - 7 is exponent, Modify
    at will"
   (let ((sign (logand integer #x80000000))
         (mantissa (ash (logand integer #x7FFFFF00) -8))
         (exponent (logand integer #xFF)))
     (float (* (if (zerop sign) 1 -1) mantissa (expt 10 exponent)))))

CL-USER 14 > (int32-to-float #x00000102)
100.0

CL-USER 15 > (int32-to-float #x80000102)
-100.0

CL-USER 16 >

Wade
From: Wade Humeniuk
Subject: Re: Converting bits to FLOAT
Date: 
Message-ID: <440Se.252949$on1.218930@clgrps13>
Wade Humeniuk wrote:

> 
> (defun int32-to-float (integer)
>   "Bit 31 is sign, bits 8 - 30 is mantissa, bits 0 - 7 is exponent, Modify
>    at will"
>   (let ((sign (logand integer #x80000000))
>         (mantissa (ash (logand integer #x7FFFFF00) -8))
>         (exponent (logand integer #xFF)))
>     (float (* (if (zerop sign) 1 -1) mantissa (expt 10 exponent)))))
> 

Oops.. forgot the sign of the exponent, but you get the idea.
Also if I am not mistaken there have been previous posts
with just the code you are looking for.

Wade
From: Peter Seibel
Subject: Re: Converting bits to FLOAT
Date: 
Message-ID: <m2r7c7tj45.fsf@gigamonkeys.com>
Denis Bueno <·······@mail.gatech.edu> 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           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Denis Bueno
Subject: Re: Converting bits to FLOAT
Date: 
Message-ID: <gtg385h-57D025.15452002092005@news-int.gatech.edu>
In article <··············@gigamonkeys.com>,
 Peter Seibel <·····@gigamonkeys.com> wrote:

> Denis Bueno <·······@mail.gatech.edu> 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.)

[snip useful code]

Thanks, Peter!

It appears, under light testing, to work very well.

-Denis
From: Pascal Bourguignon
Subject: Re: Converting bits to FLOAT
Date: 
Message-ID: <87slwnupnx.fsf@thalassa.informatimago.com>
Denis Bueno <·······@mail.gatech.edu> 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....

Here's how I did it:

;; [GPL code from
;;   ··············@cvs.informatimago.com:/cvs/common/common-lisp/heap.lisp
;; ]

(defmacro wsiosbp (&body body)
  (let ((vpack (gensym)))
    `(let ((,vpack *package*))
       (with-standard-io-syntax
           (let ((*package* ,vpack))
             ,@body)))))

(defmacro gen-ieee-encoding (name type exponent-bits mantissa-bits)
  ;; Thanks to ivan4th (········@nat-msk-01.ti.ru) for correcting an off-by-1
  (wsiosbp
   `(progn
      (defun ,(intern (format nil "~A-TO-IEEE-754" name))  (float)
        (multiple-value-bind (mantissa exponent sign) 
            (integer-decode-float float)
          (dpb (if (minusp sign) 1 0)
               (byte 1 ,(1- (+ exponent-bits mantissa-bits)))
               (dpb (+ ,(+ (- (expt 2 (1- exponent-bits)) 2) mantissa-bits)
                       exponent)
                    (byte ,exponent-bits ,(1- mantissa-bits))
                    (ldb (byte ,(1- mantissa-bits) 0) mantissa)))))
      (defun ,(intern (format nil "IEEE-754-TO-~A" name))  (ieee)
        (let ((aval (scale-float
                     (coerce
                      (dpb 1 (byte 1 ,(1- mantissa-bits))
                           (ldb (byte ,(1- mantissa-bits) 0) ieee))
                      ,type)
                     (- (ldb (byte ,exponent-bits ,(1- mantissa-bits))
                             ieee) 
                        ,(1- (expt 2 (1- exponent-bits)))
                        ,(1- mantissa-bits)))))
          (if (zerop (ldb (byte 1 ,(1- (+ exponent-bits mantissa-bits))) ieee))
            aval
            (- aval)))))))


(gen-ieee-encoding float-32 'single-float  8 24)
(gen-ieee-encoding float-64 'double-float 11 53)



;;----------------------------------------------------------------------

(defun test-ieee-read-double ()
  (with-open-file (in "value.ieee-754-double" 
                      :direction :input :element-type '(unsigned-byte 8))
    (loop while (< (file-position in) (file-length in))
          do (loop repeat 8 for i = 1 then (* i 256)
                   for v = (read-byte in) then (+ v (* i (read-byte in))) 
                   finally (progn
                             (let ((*print-base* 16)) (princ v))
                             (princ " ")
                             (princ (IEEE-754-TO-FLOAT-64 v))
                             (terpri))))))

(defun test-ieee-read-single ()
  (with-open-file (in "value.ieee-754-single" 
                      :direction :input :element-type '(unsigned-byte 8))
    (loop while (< (file-position in) (file-length in))
          do (loop repeat 4 for i = 1 then (* i 256)
                   for v = (read-byte in) then (+ v (* i (read-byte in))) 
                   finally (progn
                             (let ((*print-base* 16)) (princ v))
                             (princ " ")
                             (princ (IEEE-754-TO-FLOAT-32 v))
                             (terpri))))))

(defun test-single-to-ieee (&rest args)
  (dolist (arg args)
    (format t "~16,8R ~A~%" 
            (float-32-to-ieee-754 (coerce arg 'single-float)) arg)))

(defun test-double-to-ieee (&rest args)
  (dolist (arg args)
    (format t "~16,16R ~A~%" 
            (float-64-to-ieee-754 (coerce arg 'double-float)) arg)))

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush