-
Notifications
You must be signed in to change notification settings - Fork 15
Floating point numbers.
(read-binary-type 'half-float stream)
(read-binary-type 'single-float stream)
(read-binary-type 'double-float stream)
(read-binary-type 'quadruple-float stream)
(read-binary-type 'octuple-float stream)
LISP-BINARY can read and write 32-bit single-precision and 64-bit double-precision IEEE 754 floating point formats, in addition to three varieties of IEEE 754 that are not directly supported by x86 hardware.
In the case of single and double-precision numbers on x86 hardware, LISP-BINARY reads them by putting their bit patterns in memory and then having the hardware interpret them.
In the case of non-hardware-supported floating-point formats (including single and double-precision on non-x86 hardware), LISP-BINARY decodes the bit patterns into RATIONAL numbers using arithmetic. This is much slower than the hardware route, but preserves the full precision of quad and octo floating point numbers.
However, just because we use RATIONALs to represent these numbers in memory does not mean they are exact. Encoding a RATIONAL to floating point will subject it to the usual rounding errors that are inherent to floating point numbers, and this will be reflected when the number is decoded. You may not get exactly the same number back that you put in. Using rationals in memory only prevents the lower-precision hardware floats from introducing even more loss of precision.
Here's an example of this phenomenon in action:
LISP-BINARY-TEST> (with-open-binary-file (out "/tmp/octo.bin" :direction :output)
(write-binary-type 22/7 'octuple-float out))
32
LISP-BINARY-TEST> (with-open-binary-file (in "/tmp/octo.bin" :direction :input)
(read-binary-type 'octuple-float in))
86764811216795659042036930840054034259385369935856288122043161670619721/27606985387162255149739023449108101809804435888681546220650096895197184
32
The ANSI Common Lisp standard does not require implementations to support floating-point infinities. As a result, some implementations support them just as well as any other programming language, while others don't provide a way to represent infinity at all.
On SBCL and CCL, infinity is represented by the implementation's built-in infinity value. These are exported from LISP-BINARY as LISP-BINARY:+INF
and LISP-BINARY:-INF
.
In other implementations, LISP-BINARY:+INF
has the value :+INF
and LISP-BINARY:-INF
has the value :-INF
.
The function LISP-BINARY:INFINITYP
can portably determine if a given value is LISP-BINARY:+INF
or LISP-BINARY:-INF
, including the ability to distinguish positive from negative infinity (via the second return value).
Some Lisp implementations can represent "quiet" NaNs. I haven't seen one that can create a "signalling" NaN without crashing. In SBCL and CCL, LISP-BINARY:QUIET-NAN
is an actual floating-point NaN, while on other platforms, it has the value :QUIET-NAN
.
The value LISP-BINARY:SIGNALLING-NAN
is :SIGNALLING-NAN
on all current platforms. If you want to attempt to create a real signalling NaN, try adding :FLOAT-SIGNALLING-NAN
to *FEATURES*
before loading the library.
The function LISP-BINARY:NANP
determines if its argument is a NaN in a portable way.