Using binary arithmetics in collect statement?
Posted: Fri Apr 01, 2011 4:11 am
Hello. I'm trying to figure out how would I write the same thing, but using "collect", because it seems like a better way to do the same thing. Here's my code:
(Yes, I know there is already a library doing this, and, for this function to be correct I'd need to handle both infinities and nans, but, I'm doing this as a learning exercise, so, I'm more bothered with better ways of utilizing basic features like loops, type system and so on).
Or if you think, that "collect" is not the way to go, please tell, what, in your opinion would be the proper way to do it. If you could explain it, it would be golden!
TIA
EDIT: I've rewritten it like so:
Which looks "cleaner" to me, yet I'd like to know about my original question about "collect".
Code: Select all
;; 0.123456
(defparameter *test-float* (list #x3F #xBF #x9A #xCF #xFA #x7E #xB6 #xBF))
(defun decode-ieee-754 (bytes)
(let ( (sign (if (logbitp 1 (first bytes)) 1 -1))
(exponent (- (logior (ash (logand (first bytes) #x7F) 4)
(ash (second bytes) -4)) 1023))
(significand (+ 4503599627370496
(ash (logand (second bytes) #xF) 48)
(loop for i from 2
with result = 0
do (setf result (+ (ash result 8) (nth i bytes)))
; This looks ugly, I'd rather use "collect" here
when (= i 7) return result))))
(format t "~&sign:~15T~b2,~&exponent:~15T~b2,~&significand:~15T~b2~&" sign exponent significand)
(* sign (/ significand (ash 1 (- 52 exponent))))))
(format t "result: ~F~&" (decode-ieee-754 *test-float*))
Or if you think, that "collect" is not the way to go, please tell, what, in your opinion would be the proper way to do it. If you could explain it, it would be golden!
TIA

EDIT: I've rewritten it like so:
Code: Select all
;; 0.123456
(defparameter *test-float* (list #x3F #xBF #x9A #xCF #xFA #x7E #xB6 #xBF))
(defun decode-ieee-754 (bytes)
(let ( (sign (if (logbitp 1 (first bytes)) 1 -1))
(exponent (- (logior (ash (logand (first bytes) #x7F) 4)
(ash (second bytes) -4)) 1023))
(significand (+ 4503599627370496
(ash (logand (second bytes) #xF) 48)
(reduce #'(lambda (x y) (+ (ash x 8) y))
(subseq bytes 2)))))
(format t "~&sign:~15T~b2,~&exponent:~15T~b2,~&significand:~15T~b2~&" sign exponent significand)
(* sign (/ significand (ash 1 (- 52 exponent))))))
(format t "result: ~F~&" (decode-ieee-754 *test-float*))