Byte specifiers are objects of built-in type BYTE,
not INTEGER
s.
When a mathematical function may return an exact (RATIONAL
) or
inexact (FLOAT
) result, it always returns the exact result.
There are four floating point types: SHORT-FLOAT
,
SINGLE-FLOAT
, DOUBLE-FLOAT
and LONG-FLOAT
:
type | sign | mantissa | exponent | comment |
---|---|---|---|---|
SHORT-FLOAT | 1 bit | 16+1 bits | 8 bits | immediate |
SINGLE-FLOAT | 1 bit | 23+1 bits | 8 bits | IEEE 754 |
DOUBLE-FLOAT | 1 bit | 52+1 bits | 11 bits | IEEE 754 |
LONG-FLOAT | 1 bit | >=64 bits | 32 bits | variable length |
The single and double float formats are those of the IEEE 754
“Standard for Binary Floating-Point Arithmetic”,
except that CLISP does not support features like
±0
, ±inf
,
NaN
, gradual underflow, etc.
Common Lisp does not make use of these features, so, to reduce portability
problems, CLISP by design returns the same floating point results on
all platforms (CLISP has a floating-point emulation built in for
platforms that do not support IEEE 754). Note that
NaN
in your program, your program is broken, so you will spend time
determining where the NaN
came from.
It is better to SIGNAL
an ERROR
in this case.LONG-FLOAT
s of
variable precision - it does not
need unnormalized floats.
This is why *FEATURES*
does not contain the
:IEEE-FLOATING-POINT
keyword.
Arbitrary Precision Floats. LONG-FLOAT
s have variable mantissa length, which is a
multiple of 16 (or 32, depending on the word size of the processor).
The default length used when LONG-FLOAT
s are READ
is given by the
place (
. It can be set by EXT:LONG-FLOAT-DIGITS
)(
,
where SETF
(EXT:LONG-FLOAT-DIGITS
) n
)n
is a positive INTEGER
. E.g., (
sets the default precision of SETF
(EXT:LONG-FLOAT-DIGITS
)
3322)LONG-FLOAT
s to about
1000 decimal digits.
The floating point contagion is controlled by the variable
CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*
. When it is non-NIL
, contagion is done as per the
[ANSI CL]: SHORT-FLOAT
→ SINGLE-FLOAT
→
DOUBLE-FLOAT
→ LONG-FLOAT
.
1.5
is actually 1.5±0.05
.
Consider adding 1.5
and 1.75
.
[ANSI CL] requires that (+
1.5 1.75)
return 3.25
, while traditional CLISP would return
3.3
. The implied random variables are:
3.25±0.005
and 3.3±0.05
.
Note that the traditional CLISP way does
lie about the mean: the mean is 3.25
and
nothing else, while the standard way
could be lying about the deviation
(accuracy): if the implied accuracy of 1.5 (0.05)
is its actual accuracy, then the accuracy of the result cannot be
smaller that that. Therefore, since Common Lisp has no way of knowing the
actual accuracy, [ANSI CL] (and all the other standard engineering
programming languages, like C, Fortran
etc) decides that keeping the accuracy correct is the business of the
programmer, while the language should preserve what it can - the precision.
E(x2) -
E(x)2
can be negative!)
The user should not mix floats of different precision (that's what
CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*
is for), but one should not be penalized for this too
harshly.When CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*
is NIL
, the traditional CLISP method is used,
namely the result of an arithmetic operation whose arguments are of
different float types is rounded to the float format of the shortest
(least precise) of the arguments: RATIONAL
→
LONG-FLOAT
→ DOUBLE-FLOAT
→ SINGLE-FLOAT
→ SHORT-FLOAT
(in contrast to 12.1.4.4 Rule of Float Precision
Contagion!)
{1.0 ± 1e-8} + {1.0 ± 1e-16} = {2.0 ±
1e-8}
. So, if we add 1.0s0
and
1.0d0
, we should get 2.0s0
.
(-
(+
1.7 PI
) PI
)
should not return 1.700000726342836417234L0
, it
should return 1.7f0
(or
1.700001f0
if there were rounding errors).
SHORT-FLOAT
s,
a LONG-FLOAT
(like PI
) happens to be used, the long precision
should not propagate throughout all the intermediate values.
Otherwise, the long result would look precise, but its accuracy is
only that of a SHORT-FLOAT
; furthermore much computation time
would be lost by calculating with LONG-FLOAT
s when only
SHORT-FLOAT
s would be needed.
If the variable CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*
is non-NIL
, a WARNING
is emitted for
every coercion involving different floating-point types.
As explained above, float precision contagion is not a good idea.
You can avoid the contagion by doing all your computations with the
same floating-point type (and using FLOAT
to convert all constants,
e.g., PI
, to your preferred type).
This variable helps you eliminate all occurrences of float
precision contagion: set it to T
to have CLISP SIGNAL
a
WARNING
on float precision contagion; set it to ERROR
to have
CLISP SIGNAL
an ERROR
on float precision contagion, so that you
can look at the stack backtrace.
The contagion between floating point and rational numbers is controlled
by the variable CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*
. When it is non-NIL
, contagion is done as per
the [ANSI CL]: RATIONAL
→ FLOAT
.
When CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*
is NIL
, the traditional CLISP method is used,
namely if the result is mathematically an exact rational number, this
rational number is returned (in contrast to 12.1.4.1 Rule of Float and Rational
Contagion!)
CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*
has an effect only in those few cases when the mathematical
result is exact although one of the arguments is a floating-point number,
such as (
, *
0 1.618)(
,
/
0 1.618)(
, ATAN
0 1.0)(
,
EXPT
2.0 0)(
.PHASE
2.718)
If the variable CUSTOM:*WARN-ON-FLOATING-POINT-RATIONAL-CONTAGION*
is non-NIL
, a WARNING
is emitted for
every avoidable coercion from a rational number to a floating-point number.
You can avoid such coercions by calling FLOAT
to convert the particular
rational numbers to your preferred floating-point type.
This variable helps you eliminate all occurrences of avoidable
coercions to a floating-point number when a rational number result
would be possible: set it to T
to have CLISP SIGNAL
a WARNING
in such situations; set it to ERROR
to have CLISP SIGNAL
an
ERROR
in such situations, so that you can look at the stack
backtrace.
CUSTOM:*PHASE-ANSI*
A similar variable, CUSTOM:*PHASE-ANSI*
, controls the return
value of PHASE
when the argument is an exact nonnegative REAL
.
Namely, if CUSTOM:*PHASE-ANSI*
is non-NIL
, it returns a floating-point zero;
if CUSTOM:*PHASE-ANSI*
is NIL
, it returns an exact zero. Example:
(
PHASE
2/3)
Complex numbers can have a real part and an imaginary part of
different types. For example, (
evaluates to
the number SQRT
-9.0)#C(0 3.0)
,
which has a real part of exactly 0
,
not only 0.0
(which would mean “approximately 0”).
The type specifier for this is (
, and COMPLEX
INTEGER
SINGLE-FLOAT
)(
in general.COMPLEX
type-of-real-part
type-of-imaginary-part
)
The type specifier (
is equivalent to COMPLEX
type
)(
.COMPLEX
type
type
)
Complex numbers can have a real part and an imaginary part of
different types. If the imaginary part is EQL
to 0
,
the number is automatically converted to a real number.
This has the advantage that
(
- instead of
evaluating to LET
((x (SQRT
-9.0))) (* x x))#C(-9.0 0.0)
, with x
= #C(0.0 3.0)
- evaluates to
#C(-9.0 0)
=
-9.0
,
with x
= #C(0 3.0)
.
These notes document CLISP version 2.41 | Last modified: 2006-10-13 |