lqml/examples/meshtastic/hacks/float-features.lisp

508 lines
18 KiB
Common Lisp

#|
This file is a part of float-features
(c) 2018 Shirakumo http://tymoon.eu (shinmera@tymoon.eu)
Author: Nicolas Hafner <shinmera@tymoon.eu>
|#
(defpackage #:float-features
(:nicknames #:org.shirakumo.float-features)
(:use #:cl)
(:export
#:short-float-positive-infinity
#:short-float-negative-infinity
#:short-float-nan
#:single-float-positive-infinity
#:single-float-negative-infinity
#:single-float-nan
#:double-float-positive-infinity
#:double-float-negative-infinity
#:double-float-nan
#:long-float-positive-infinity
#:long-float-negative-infinity
#:long-float-nan
#:float-infinity-p
#:float-nan-p
#:with-float-traps-masked
#:short-float-bits
#:single-float-bits
#:double-float-bits
#:long-float-bits
#:bits-short-float
#:bits-single-float
#:bits-double-float
#:bits-long-float))
(in-package #:org.shirakumo.float-features)
(defconstant short-float-positive-infinity
#+ccl 1S++0
#+clasp ext:short-float-positive-infinity
#+cmucl extensions:short-float-positive-infinity
#+ecl ext:short-float-positive-infinity
#+mezzano mezzano.extensions:short-float-positive-infinity
#+mkcl ext:short-float-positive-infinity
#+sbcl sb-ext:short-float-positive-infinity
#+lispworks 1S++0
#+allegro (coerce excl:*infinity-single* 'short-float)
#-(or ccl clasp cmucl ecl mezzano mkcl sbcl lispworks allegro)
most-positive-short-float)
(defconstant short-float-negative-infinity
#+ccl -1S++0
#+clasp ext:short-float-negative-infinity
#+cmucl extensions:short-float-negative-infinity
#+ecl ext:short-float-negative-infinity
#+mezzano mezzano.extensions:short-float-negative-infinity
#+mkcl ext:short-float-negative-infinity
#+sbcl sb-ext:short-float-negative-infinity
#+lispworks -1S++0
#+allegro (coerce excl:*negative-infinity-single* 'short-float)
#-(or ccl clasp cmucl ecl mezzano mkcl sbcl lispworks allegro)
most-negative-short-float)
(defconstant single-float-positive-infinity
#+abcl extensions:single-float-positive-infinity
#+allegro excl:*infinity-single*
#+ccl 1F++0
#+clasp ext:single-float-positive-infinity
#+cmucl extensions:single-float-positive-infinity
#+ecl ext:single-float-positive-infinity
#+mezzano mezzano.extensions:single-float-positive-infinity
#+mkcl mkcl:single-float-positive-infinity
#+sbcl sb-ext:single-float-positive-infinity
#+lispworks 1F++0
#-(or abcl allegro ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-positive-single-float)
(defconstant single-float-negative-infinity
#+abcl extensions:single-float-negative-infinity
#+allegro excl:*negative-infinity-single*
#+ccl -1F++0
#+clasp ext:single-float-negative-infinity
#+cmucl extensions:single-float-negative-infinity
#+ecl ext:single-float-negative-infinity
#+mezzano mezzano.extensions:single-float-negative-infinity
#+mkcl mkcl:single-float-negative-infinity
#+sbcl sb-ext:single-float-negative-infinity
#+lispworks -1F++0
#-(or abcl allegro ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-negative-single-float)
(defconstant double-float-positive-infinity
#+abcl extensions:double-float-positive-infinity
#+allegro excl:*infinity-double*
#+ccl 1D++0
#+clasp ext:double-float-positive-infinity
#+cmucl extensions:double-float-positive-infinity
#+ecl ext:double-float-positive-infinity
#+mezzano mezzano.extensions:double-float-positive-infinity
#+mkcl mkcl:double-float-positive-infinity
#+sbcl sb-ext:double-float-positive-infinity
#+lispworks 1D++0
#-(or abcl allegro ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-positive-double-float)
(defconstant double-float-negative-infinity
#+abcl extensions:double-float-negative-infinity
#+allegro excl:*negative-infinity-double*
#+ccl -1D++0
#+clasp ext:double-float-negative-infinity
#+cmucl extensions:double-float-negative-infinity
#+ecl ext:double-float-negative-infinity
#+mezzano mezzano.extensions:double-float-negative-infinity
#+mkcl mkcl:double-float-negative-infinity
#+sbcl sb-ext:double-float-negative-infinity
#+lispworks -1D++0
#-(or abcl allegro ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-negative-double-float)
(defconstant long-float-positive-infinity
#+ccl 1L++0
#+clasp ext:long-float-positive-infinity
#+cmucl extensions:long-float-positive-infinity
#+ecl ext:long-float-positive-infinity
#+mezzano mezzano.extensions:long-float-positive-infinity
#+mkcl ext:long-float-positive-infinity
#+sbcl sb-ext:long-float-positive-infinity
#+lispworks 1L++0
#-(or ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-positive-long-float)
(defconstant long-float-negative-infinity
#+ccl -1L++0
#+clasp ext:long-float-negative-infinity
#+cmucl extensions:long-float-negative-infinity
#+ecl ext:long-float-negative-infinity
#+mezzano mezzano.extensions:long-float-negative-infinity
#+mkcl ext:long-float-negative-infinity
#+sbcl sb-ext:long-float-negative-infinity
#+lispworks -1L++0
#-(or ccl clasp cmucl ecl mezzano mkcl sbcl lispworks)
most-negative-long-float)
(declaim (inline float-infinity-p
float-nan-p))
(defun float-infinity-p (float)
#+abcl (system:float-infinity-p float)
#+allegro (excl:infinityp float)
#+ccl (ccl::infinity-p float)
#+clasp (ext:float-infinity-p float)
#+cmucl (extensions:float-infinity-p float)
#+ecl (ext:float-infinity-p float)
#+mezzano (mezzano.extensions:float-infinity-p float)
#+sbcl (sb-ext:float-infinity-p float)
#-(or abcl allegro ccl clasp cmucl ecl mezzano sbcl)
(etypecase float
(short-float (or (= float short-float-negative-infinity)
(= float short-float-positive-infinity)))
(single-float (or (= float single-float-negative-infinity)
(= float single-float-positive-infinity)))
(double-float (or (= float double-float-negative-infinity)
(= float double-float-positive-infinity)))
(long-float (or (= float long-float-negative-infinity)
(= float long-float-positive-infinity)))))
(defun float-nan-p (float)
#+abcl (system:float-nan-p float)
#+allegro (excl:nanp float)
#+ccl (and (ccl::nan-or-infinity-p float)
(not (ccl::infinity-p float)))
#+clasp (ext:float-nan-p float)
#+cmucl (extensions:float-nan-p float)
#+ecl (ext:float-nan-p float)
#+mezzano (mezzano.extensions:float-nan-p float)
#+sbcl (sb-ext:float-nan-p float)
#+lispworks (sys::nan-p float)
#-(or abcl allegro ccl clasp cmucl ecl mezzano sbcl lispworks)
(/= float float))
(defun keep (list &rest keeps)
(loop for item in list
when (find item keeps)
collect item))
(defmacro with-float-traps-masked (traps &body body)
(let ((traps (etypecase traps
((eql T) '(:underflow :overflow :inexact :invalid :divide-by-zero :denormalized-operand))
(list traps))))
#+abcl
(let ((previous (gensym "PREVIOUS")))
`(let ((,previous (extensions:get-floating-point-modes)))
(unwind-protect
(progn
(extensions:set-floating-point-modes
:traps ',(keep traps :overflow :underflow))
NIL ,@body)
(apply #'extensions:set-floating-point-modes ,previous))))
#+ccl
(let ((previous (gensym "PREVIOUS"))
(traps (loop for thing in traps
for trap = (case thing
(:underflow :underflow)
(:overflow :overflow)
(:divide-by-zero :division-by-zero)
(:invalid :invalid)
(:inexact :inexact))
when trap collect trap)))
`(let ((,previous (ccl:get-fpu-mode)))
(unwind-protect
(progn
(ccl:set-fpu-mode
,@(loop for trap in traps
collect trap collect NIL))
NIL ,@body)
(apply #'ccl:set-fpu-mode ,previous))))
#+clisp
(if (find :underflow)
`(ext:without-floating-point-underflow
,@body)
`(progn
,@body))
#+cmucl
`(extensions:with-float-traps-masked #+x86 ,traps #-x86 ,(remove :denormalized-operand traps)
,@body)
#+ecl
(let ((previous (gensym "PREVIOUS")))
`(let ((,previous (si::trap-fpe :last T)))
(unwind-protect
(progn
,@(loop for trap in traps
for keyword = (case trap
(:underlow :floating-point-underflow)
(:overflow :floating-point-overflow)
(:inexact :floating-point-inexact)
(:invalid :floating-point-invalid)
(:divide-by-zero :division-by-zero))
when keyword collect `(si::trap-fpe ,keyword T))
NIL ,@body)
(si::trap-fpe ,previous NIL))))
#+clasp
`(ext:with-float-traps-masked ,traps
,@body)
#+mezzano
(let ((previous (gensym "PREVIOUS"))
(traps (loop for thing in traps
for trap = (case thing
(:underflow :underflow)
(:overflow :overflow)
(:divide-by-zero :divide-by-zero)
(:invalid :invalid-operation)
(:inexact :precision)
#+x86-64
(:denormalized-operand :denormal-operand))
when trap collect trap)))
`(let ((,previous (mezzano.runtime::get-fpu-mode)))
(unwind-protect
(progn
(mezzano.runtime::set-fpu-mode
,@(loop for trap in traps
collect trap collect T))
NIL ,@body)
(apply #'mezzano.runtime::set-fpu-mode ,previous))))
#+sbcl
`(sb-int:with-float-traps-masked #+x86 ,traps #-x86 ,(remove :denormalized-operand traps)
,@body)
#-(or abcl ccl clasp clisp cmucl ecl mezzano sbcl)
(declare (ignore traps))
#-(or abcl ccl clasp clisp cmucl ecl mezzano sbcl)
`(progn ,@body)))
(declaim (inline short-float-bits
single-float-bits
double-float-bits
long-float-bits
bits-short-float
bits-single-float
bits-double-float
bits-long-float))
(declaim (ftype (function (T) (unsigned-byte 16)) short-float-bits))
(defun short-float-bits (float)
(declare (ignorable float))
#+mezzano
(mezzano.extensions:short-float-to-ieee-binary16 float)
#+(or ecl sbcl cmucl allegro ccl
(and 64-bit lispworks))
(let* ((bits (single-float-bits float))
(sign (ldb (byte 1 31) bits))
(exp (- (ldb (byte 8 23) bits) 127))
(sig (ldb (byte 23 0) bits)))
(cond
((or (eql 0s0 float)
(< exp -24))
;;underflow
(ash sign 15))
((< exp -14)
;; encode as denormal if possible
(logior (ash sign 15)
0
(ash (ldb (byte 11 13)
(logior (ash 1 23) sig))
(+ exp 14))))
((< exp 16)
;; encode directly
(logior (ash sign 15)
(ash (+ exp 15) 10)
(ash sig -13)))
((zerop sig)
;; infinity
(if (zerop sign)
#b0111110000000000
#b1111110000000000))
(t
;;NaN
(logior (ash sign 15)
(ash #x1f 10)
(ldb (byte 10 13) sig)))))
;; clisp short-float is 1+8+16
;; 32bit lispworks 5+ is 1+8+??, lw4 only has double
;; not sure about others?
#- (or mezzano ecl sbcl cmucl allegro ccl (and 64-bit lispworks))
(progn float (error "Implementation not supported.")))
(declaim (ftype (function (T) (unsigned-byte 32)) single-float-bits))
(defun single-float-bits (float)
#+abcl
(ldb (byte 32 0) (system:single-float-bits float))
#+allegro
(multiple-value-bind (high low) (excl:single-float-to-shorts float)
(logior low (ash high 16)))
#+ccl
(ccl::single-float-bits float)
#+clasp
(ext:single-float-to-bits float)
#+cmucl
(ldb (byte 32 0) (kernel:single-float-bits float))
#+ecl
(si:single-float-bits float)
#+lispworks
(let ((v (sys:make-typed-aref-vector 4)))
(declare (optimize (speed 3) (float 0) (safety 0)))
(declare (dynamic-extent v))
(setf (sys:typed-aref 'single-float v 0) float)
(sys:typed-aref '(unsigned-byte 32) v 0))
#+mezzano
(mezzano.extensions:single-float-to-ieee-binary32 float)
#+sbcl
(ldb (byte 32 0) (sb-kernel:single-float-bits float))
#-(or abcl allegro ccl clasp cmucl ecl lispworks mezzano sbcl)
(progn float (error "Implementation not supported.")))
(declaim (ftype (function (T) (unsigned-byte 64)) double-float-bits))
(defun double-float-bits (float)
#+abcl
(logior (system::double-float-low-bits float)
(ash (system::double-float-high-bits float) 32))
#+allegro
(multiple-value-bind (s3 s2 s1 s0) (excl:double-float-to-shorts float)
(logior s0 (ash s1 16) (ash s2 32) (ash s3 48)))
#+ccl
(multiple-value-bind (high low) (ccl::double-float-bits float)
(logior low (ash high 32)))
#+clasp
(ext:double-float-to-bits float)
#+cmucl
(ldb (byte 64 0)
(logior (kernel:double-float-low-bits float)
(ash (kernel:double-float-high-bits float) 32)))
#+ecl
(si:double-float-bits float)
#+lispworks
(let ((v (sys:make-typed-aref-vector 8)))
(declare (optimize (speed 3) (float 0) (safety 0)))
(declare (dynamic-extent v))
(setf (sys:typed-aref 'double-float v 0) float)
#+x86-64 (sys:typed-aref '(unsigned-byte 64) v 0)
#-x64-64 (logior (sys:typed-aref '(unsigned-byte 32) v 0)
(ash (sys:typed-aref '(unsigned-byte 32) v 4) 32)))
#+mezzano
(mezzano.extensions:double-float-to-ieee-binary64 float)
#+sbcl
(ldb (byte 64 0)
(logior (sb-kernel:double-float-low-bits float)
(ash (sb-kernel:double-float-high-bits float) 32)))
#-(or abcl allegro ccl clasp cmucl ecl lispworks mezzano sbcl)
(progn float (error "Implementation not supported.")))
(declaim (ftype (function (T) (unsigned-byte 128)) long-float-bits))
(defun long-float-bits (float)
(declare (ignore float))
(error "Implementation not supported."))
(declaim (ftype (function (T) short-float) bits-short-float))
(defun bits-short-float (bits)
(declare (ignorable bits))
#+mezzano
(mezzano.extensions:ieee-binary16-to-short-float bits)
#+ (or ecl sbcl cmucl allegro ccl
(and 64-bit lispworks))
(let ((sign (ldb (byte 1 15) bits))
(exp (ldb (byte 5 10) bits))
(sig (ldb (byte 10 0) bits)))
(if (= exp 31)
(cond
((not (zerop sig))
;; NaNs
(bits-single-float
(logior (ash sign 31)
(ash #xff 23)
;; store in high-bit to preserve quiet/signalling
(ash sig 13))))
;; infinities
((zerop sign)
single-float-positive-infinity)
(t
single-float-negative-infinity))
(cond
((= 0 exp sig)
;; +- 0
(if (zerop sign) 0s0 -0s0))
((zerop exp)
;; denormals -> single floats
(let ((d (- 11 (integer-length sig))))
(setf exp (- -14 d))
(setf sig (ldb (byte 11 0) (ash sig (1+ d))))
(bits-single-float
(logior (ash sign 31)
(ash (+ exp 127) 23)
(ash sig #.(- 23 11))))))
(t
;; normal numbers
(bits-single-float
(logior (ash sign 31)
(ash (+ exp #.(+ 127 -15)) 23)
(ash sig #.(- 23 10))))))))
#- (or mezzano ecl sbcl cmucl allegro ccl (and 64-bit lispworks))
(progn bits (error "Implementation not supported.")))
(declaim (ftype (function (T) single-float) bits-single-float))
(defun bits-single-float (bits)
#+abcl
(system:make-single-float bits)
#+allegro
(excl:shorts-to-single-float (ldb (byte 16 16) bits) (ldb (byte 16 0) bits))
#+ccl
(ccl::host-single-float-from-unsigned-byte-32 bits)
#+clasp
(ext:bits-to-single-float bits)
#+cmucl
(flet ((s32 (x)
(logior x (- (mask-field (byte 1 31) x))) ))
(kernel:make-single-float (s32 bits)))
#+ecl
(si:bits-single-float bits)
#+lispworks
(let ((v (sys:make-typed-aref-vector 4)))
(declare (optimize speed (float 0) (safety 0)))
(declare (dynamic-extent v))
(setf (sys:typed-aref '(unsigned-byte 32) v 0) bits)
(sys:typed-aref 'single-float v 0))
#+mezzano
(mezzano.extensions:ieee-binary32-to-single-float bits)
#+sbcl
(sb-kernel:make-single-float
(sb-c::mask-signed-field 32 (the (unsigned-byte 32) bits)))
#-(or abcl allegro ccl clasp cmucl ecl lispworks mezzano sbcl)
(progn bits (error "Implementation not supported.")))
(declaim (ftype (function (T) double-float) bits-double-float))
(defun bits-double-float (bits)
#+abcl
(system:make-double-float bits)
#+allegro
(excl:shorts-to-double-float
(ldb (byte 16 48) bits) (ldb (byte 16 32) bits) (ldb (byte 16 16) bits) (ldb (byte 16 0) bits))
#+ccl
(ccl::double-float-from-bits (ldb (byte 32 32) bits) (ldb (byte 32 0) bits))
#+clasp
(ext:bits-to-double-float bits)
#+cmucl
(flet ((s32 (x)
(logior x (- (mask-field (byte 1 31) x))) ))
(kernel:make-double-float (s32 (ldb (byte 32 32) bits))
(ldb (byte 32 0) bits)))
#+ecl
(si:bits-double-float bits)
#+lispworks
(let ((v (sys:make-typed-aref-vector 8)))
(declare (optimize speed (float 0) (safety 0)))
(declare (dynamic-extent v))
#+x86-64 (setf (sys:typed-aref '(unsigned-byte 64) v 0) bits)
#-x86-64 (setf (sys:typed-aref '(unsigned-byte 32) v 0) (ldb (byte 32 0) bits)
(sys:typed-aref '(unsigned-byte 32) v 4) (ldb (byte 32 32) bits))
(sys:typed-aref 'double-float v 0))
#+mezzano
(mezzano.extensions:ieee-binary64-to-double-float bits)
#+sbcl
(sb-kernel:make-double-float
(sb-c::mask-signed-field 32 (ldb (byte 32 32) (the (unsigned-byte 64) bits)))
(ldb (byte 32 0) bits))
#-(or abcl allegro ccl clasp cmucl ecl lispworks mezzano sbcl)
(progn bits (error "Implementation not supported.")))
(declaim (ftype (function (T) long-float) bits-long-float))
(defun bits-long-float (bits)
(declare (ignore bits))
(error "Implementation not supported."))