[Top][All Lists]
[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
<address@hidden> 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 <address@hidden>
;; 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:address@hidden Better Safe Than Sorry
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: IEEE-754 binary rep functions,
Ehud Karni <=