help-gnu-emacs
[Top][All Lists]
Advanced

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

Re: IEEE-754 binary rep functions


From: Ehud Karni
Subject: Re: IEEE-754 binary rep functions
Date: Wed, 23 Oct 2002 16:19:53 +0200

On Tue, 22 Oct 2002 08:20:55 +0200, Heinz Eriksson
   <heinz.eriksson@era.ericsson.se> wrote:
> 
> How would one write elisp functions to convert
> to and from the binary representation of a
> IEEE-754 (single precision) floating point number?
> I don't care about NaN etc.

Bellow is my code for the conversions you asked for.
Save the code to a file "IEEE-754.el" and load it into your Emacs
session using `load-file'.

To convert from number to hex representation do:
    (setq HEX-VAL (IEEE-float-2-hex -5.678e+9))
To convert from hex representation to floating number do:
    (setq FLT-VAL (IEEE-hex-2-float "4fed0123"))

Ehud.



;; IEEE-754.el - convert 32 bit floating number to/from its hex
;;               (big-endian) representation according to IEEE-754
;;
;; These functions deals correctly with 0 and -/+ infinity
;; Both kind of NaN (not a number) are ignored
;;
;; written by Ehud Karni <ehud@unix.mvs.co.il>


;; References: http://www.cs.berkeley.edu/~ejr/projects/754/
;;             
http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
;;             http://www.cs.berkeley.edu/~wkahan/ieee754status/ieee754.ps
;; Conversion on-line:
;;             http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html
;; History of IEEE-754
;;             http://www.cs.berkeley.edu/~wkahan/ieee754status/754story.html


;; the value of IEEE-754 float is:
;; Normal number (normalized)
;;       ( 1 - 2*sign ) * 2 ** (exp - exp-bias) * ( 1 + mantissa / 
mantissa-divisor )
;; Very small number (De-normalized)
;;       ( 1 - 2*sign ) * 2 ** (1 - exp-bias ) * ( mantissa / mantissa-divisor )

;;
;; for a 32 bit float (sign/exp/mantissa bits = 1/8/23) ===>
;; ( 1 - 2*sign ) * 2 ** (exp - 127) * ( 1 + mantissa / 8388608 )

;; for a 64 bit float (sign/exp/mantissa bits = 1/11/52) ===>
;; ( 1 - 2*sign ) * 2 ** (exp - 1023) * ( 1 + mantissa / 4503599627370496 )

(defvar IEEE-sign-mlt 128 "multiplier for sign")                       ;  1 bits
(defvar IEEE-exp-bias 127 "exponent bias for float"                    ;  8 bits
(defvar IEEE-mantissa-divisor ?\x800000 "mantissa divisor for float")  ; 23 bits
(defvar IEEE-float-mantissa-divisor (/ 1.0 (float IEEE-mantissa-divisor))
                          "floated 1 / mantissa divisor")


(defun IEEE-float-2-hex (FNUM)
  "Convert a floating point number FNUM to 8 Hex digits string (big endian)"
       (interactive "nEnter float to convert: ")
       (or (floatp-safe FNUM)
           (setq FNUM (float FNUM)))
       (let ((IEEE-sign 0)
             (IEEE-exp  0)
             (IEEE-mantissa 0)
              hex
            )
           (and (< FNUM 0)                         ; negative
               (setq IEEE-sign IEEE-sign-mlt)      ; yes, sign=1 (* 2**7)
               (setq FNUM (- FNUM)))               ; negate (abs) it
           (cond
               ((= FNUM 0))                        ; Zero - we all set
               ((= FNUM 1e+INF)                    ; infinite ?
                       (setq IEEE-exp IEEE-exp-bias))  ; exp = max, mantissa = 0

               (t                                  ;; real float
                   (setq IEEE-exp (floor (log FNUM 2.0)))      ; exponent [ log 
2 FNUM ] - integer
                   (if (<= IEEE-exp (- IEEE-exp-bias))         ; check for 
De-normalized number
                       (setq IEEE-exp 0                        ; really - 
IEEE-exp-bias
                             IEEE-mantissa (truncate (* IEEE-mantissa-divisor
                                       0.5 FNUM (expt 2.0 IEEE-exp-bias))))
               ;; normal float
                       (setq IEEE-mantissa (truncate (* IEEE-mantissa-divisor
                                       (- (/ FNUM (expt 2.0 IEEE-exp)) 1))))
                       (setq IEEE-exp (+ IEEE-exp IEEE-exp-bias))) ;; offset-ed 
exp
               ))
           (setq hex (format "%02X%06X" (+ IEEE-sign (/ IEEE-exp 2))
                                         (+ IEEE-mantissa
                                            (* (% IEEE-exp 2) 
IEEE-mantissa-divisor))))

;;         (message "Float=%f sign=%d, exp=%d, mant=%d  HEX=%s"
;;                  FNUM IEEE-sign IEEE-exp IEEE-mantissa hex)

           hex))



(defun IEEE-hex-2-float (HEX)
  "Convert an 8 Hex digits string (big endian) to floating point number"
       (interactive "sEnter hex value (8 hex digits): ")
       (if (or (not (stringp HEX))
               (/= (length HEX) 8)
               (string-match "[^0-9a-fA-F]" HEX))
           (error "Arg must be a string of EXACTLY 8 hex (1-8, a-f, A-F) 
digits"))

       (let ((S-EXP (string-to-number (substring HEX 0 2) 16))
             (MANTISSA (string-to-number (substring HEX 2) 16))
             (RSLT 1)
              IEEE-sign
              IEEE-exp
              IEEE-mantissa
            )
           (setq IEEE-mantissa (logior MANTISSA IEEE-mantissa-divisor)) ; 
always set upper bit
           (if (= IEEE-mantissa IEEE-mantissa-divisor)             ; = --> zero 
mantissa, check special cases
               (cond
                   ((string-equal HEX "00000000")
                                       (setq RSLT (float 0)))      ; Zero
                   ((string-equal HEX "3F800000")
                                       (setq RSLT  1e+INF))        ; + infinity
                   ((string-equal HEX "BF800000")
                                       (setq RSLT -1e+INF))        ; - infinity
               ))
           (if (/= RSLT 1)
                   RSLT                                            ; special 
cases (0, infinity)

               (setq IEEE-sign (ash S-EXP -7))                     ; shift 
right 7 bits
               (setq IEEE-exp (+ (ash (% S-EXP IEEE-sign-mlt) 1)   ; shift 
(part) exp 1
                                 (ash MANTISSA -23)))              ; 1 bit from 
mantissa
               (if (= IEEE-exp 0)                                  ; 
De-normalized ?
                   (setq IEEE-mantissa (ash
                           (logxor IEEE-mantissa IEEE-mantissa-divisor) 1))) ; 
clear upper bit
;;             (message "Hex=%s sign=%d, exp=%d, mant=%d"
;;                      HEX IEEE-sign IEEE-exp IEEE-mantissa)

               (*                                                  ; result 
float
                   (- 1 IEEE-sign IEEE-sign)                       ; sign
                   (expt 2.0 (- IEEE-exp IEEE-exp-bias))           ; 2 ** 
exponent (un-biased)
                   (float IEEE-mantissa)                           ; mantissa 
part
                   IEEE-float-mantissa-divisor                     ; 1 / 
mantissa divisor
               ))))


;; For test do (note: the re-computed float is NOT rounded)
;; (IEEE-hex-2-float (IEEE-float-2-hex 123.456))

;; ---------------------- IEEE-754.el ends here -----------------------


-- 
 Ehud Karni           Tel: +972-3-7966-561  /"\
 Mivtach - Simon      Fax: +972-3-7966-667  \ /  ASCII Ribbon Campaign
 Insurance agencies   (USA) voice mail and   X   Against   HTML   Mail
 http://www.mvs.co.il  FAX:  1-815-5509341  / \
 mailto:ehud@unix.mvs.co.il                  Better  Safe  Than  Sorry




reply via email to

[Prev in Thread] Current Thread [Next in Thread]