In Common Lisp, arithmetic operations are `generic`.^{12}
The `+`

function can be passed `fixnum`

s, `bignum`

s,
`ratio`

s, and various kinds of `float`

s and
`complex`

es, in any combination. In addition to the inherent
complexity of `bignum`

and `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
even starts.

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:

- All the arguments must be known to be a good type of number.
- The result must be known to be a good type of number.
- Any intermediate values such as the result of
`(+ a b)`

in the call`(+ a b c)`

must be known to be a good type of number. - All the above numbers with good types must be of the
`same`good type. Don’t try to mix integers and floats or different float formats.

The “good types” are `(signed-byte 32)`

,
`(unsigned-byte 32)`

, `single-float`

,
`double-float`

, `(complex single-float)`

, and ```
(complex
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
`single-float`

or `double-float`

. `integer`

is not a
good type, since it might mean `bignum`

. `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 `integer`

and
`unsigned-byte`

(or non-negative integer) types are especially
useful in this regard, since they can often be strengthened to a good
integer type.

As noted above, CMUCL has support for `(complex single-float)`

and `(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
faster than `bignum`

or `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.