In Common Lisp, arithmetic operations are generic.12
+ function can be passed
ratios, and various kinds of
complexes, in any combination. In addition to the inherent
ratio operations, there is also
a lot of overhead in just figuring out which operation to do and what
contagion and canonicalization rules apply. The complexity of generic
arithmetic is so great that it is inconceivable to open code it.
Instead, the compiler does a function call to a generic arithmetic
routine, consuming many instructions before the actual computation
This is ridiculous, since even Common Lisp programs do a lot of arithmetic, and the hardware is capable of doing operations on small integers and floats with a single instruction. To get acceptable efficiency, the compiler special-cases uses of generic arithmetic that are directly implemented in the hardware. In order to open code arithmetic, several constraints must be met:
(+ a b)in the call
(+ a b c)must be known to be a good type of number.
The “good types” are
(complex single-float), and
double-float). See sections fixnums, word-integers
and float-efficiency for more discussion of good numeric types.
float is not a good type, since it might mean either
integer is not a
good type, since it might mean
rational is not
a good type, since it might mean
ratio. Note however that
these types are still useful in declarations, since type inference may
be able to strengthen a weak declaration into a good one, when it
would be at a loss if there was no declaration at all
(see type-inference). The
unsigned-byte (or non-negative integer) types are especially
useful in this regard, since they can often be strengthened to a good
As noted above, CMUCL has support for
(complex double-float). These can be unboxed and, thus,
are quite efficient. However, arithmetic with complex types such as:
(complex float) (complex fixnum)
will be significantly slower than the good complex types but is still
ratio arithmetic, since the
implementation is much simpler.
Note: don’t use
/ to divide integers unless you want the
overhead of rational arithmetic. Use
truncate even when you
know that the arguments divide evenly.
You don’t need to remember all the rules for how to get open-coded arithmetic, since efficiency notes will tell you when and where there is a problem—see efficiency-notes.
As Steele notes in CLTL II, this is a generic conception of generic, and is not to be confused with the CLOS concept of a generic function.