[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Double floats
- To: millett@sbctri.sbc.com
- Subject: Re: Double floats
- From: bill@cambridge.apple.com (Bill St. Clair)
- Date: Fri, 6 Nov 1992 11:53:18 -0600
- Cc: info-mcl
>I am tring to take a double-float number, break it down into 2 long
>integers (high-word and low-word) to send over the network conforming to
>the IEEE floating point standard. I also want to read 2 words from the
>stream and make a double-float from them. Any Ideas? Symbolics has two
>functions that do what I want: "si:dfloat-components: (double)" &
>"si:%make-double: (high low)" Any way to do this with the mac?
>
>Thanks,
>millett@sbctri.sbc.com
MCL has a function that breaks a double float into 4 fixnums:
high-mantissa, low-mantissa, exponent, and sign.
It also has a function for putting these components back together again.
ccl::fixnum-decode-float double-float
; decompose a double-float into fixnum size pieces
; returns 4 values
; hi is high 24 bits of mantissa (with the implied 1 in bit 25 if appropriate)
; lo is low 28 bits of mantissa (hi and lo are both right justified)
; exp is 11 bit exponent (the bits as they are - not unbiased; i.e. exp is >= 0)
; sign is 1 or -1
ccl::make-float-from-fixnums hi lo exp sign
; make a float from hi - high 24 bits mantissa (ignore implied higher bit)
; lo - low 28 bits mantissa
; exp - take low 11 bits
; sign - sign(sign) => result
; hi result - 1 bit sign: 11 bits exp: 20 hi bits of hi arg
; lo result - 4 lo bits of hi arg: 28 lo bits of lo arg
; no error checks, no tweaks, no nuthin
You can use these to make the integers (likely bignums) that you want:
(defun dfloat-components (dfloat)
(multiple-value-bind (hi lo exp sign) (ccl::fixnum-decode-float dfloat)
(declare (fixnum hi lo exp sign))
(values
(+ (if (< sign 0) (ash 1 31) 0)
(ash exp (- 31 11))
(ash (logand hi #xfffff0) (- 20 24)))
(+ (ash (logand hi #xf) (- 32 4))
lo))))
(defun make-double (high low)
(ccl::make-float-from-fixnums
(+ (ash (logand high #xfffff) 4)
(ash low -28))
(logand low #xfffffff)
(logand (ash high -20) #x7ff)
(if (logbitp 31 high) -1 1)))
This is not very efficient.
The following LAP versions are more efficient
(though dfloat-components still conses bignums):
(in-package :ccl)
(eval-when (:compile-toplevel :execute)
(require "LAPMACROS") ; lap-inline
(require "LISPEQU")) ; $floathi
(defun dfloat-components (dfloat)
(setq dfloat (require-type dfloat 'double-float))
(let (hi lo)
(lap-inline ()
(:variable dfloat hi lo)
(move.l (varg dfloat) atemp0)
(move.l (atemp0 $floathi) arg_z)
(jsr_subprim $sp-mklong)
(move.l acc (varg hi))
(move.l (varg dfloat) atemp0)
(move.l (atemp0 (+ $floathi 4)) arg_z)
(jsr_subprim $sp-mklong)
(move.l acc (varg lo)))
(values hi lo)))
(defun make-float (high low)
(lap-inline ()
(:variable high low)
(move.l (varg high) arg_z)
(jsr_subprim $sp-getxlong)
(move.l acc arg_y)
(move.l (varg low) arg_z)
(jsr_subprim $sp-getxlong)
(jsr_subprim $sp-makefloat)))