next up previous contents
Next: 5.11.5 Fixnums Up: 5.11 Numbers Previous: 5.11.3 Variables

5.11.4 Generic Arithmetic

       

In Common Lisp, arithmetic operations are generic.gif The + function can be passed fixnums, bignums, ratios, and various kinds of floats and complexes, 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:

The ``good types'' are (signed-byte 32), (unsigned-byte 32), single-float and double-float. See sections 5.11.5, 5.11.6 and 5.11.7 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 section 5.3). 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.

Arithmetic with complex numbers is inefficient in comparison to float and integer arithmetic. Complex numbers are always represented with a pointer descriptor (causing consing overhead), and complex arithmetic is always closed coded using the general generic arithmetic functions. But arithmetic with complex types such as:

(complex float)
(complex fixnum)
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 section 5.13.


next up previous contents
Next: 5.11.5 Fixnums Up: 5.11 Numbers Previous: 5.11.3 Variables

Raymond Toy
Mon Jul 14 09:11:27 EDT 1997