Next: Word Integers, Previous: Generic Arithmetic, Up: Numbers [Contents][Index]

A fixnum is a “FIXed precision NUMber”. In modern Common Lisp implementations, fixnums can be represented with an immediate descriptor, so operating on fixnums requires no consing or memory references. Clever choice of representations also allows some arithmetic operations to be done on fixnums using hardware supported word-integer instructions, somewhat reducing the speed penalty for using an unnatural integer representation.

It is useful to distinguish the `fixnum`

type from the fixnum
representation of integers. In Python, there is absolutely nothing
magical about the `fixnum`

type in comparison to other finite
integer types. `fixnum`

is equivalent to (is defined with
`deftype`

to be) `(signed-byte 30)`

. `fixnum`

is
simply the largest subset of integers that *can be represented*
using an immediate fixnum descriptor.

Unlike in other Common Lisp compilers, it is in no way desirable to use
the `fixnum`

type in declarations in preference to more
restrictive integer types such as `bit`

, `(integer -43 7)`

and `(unsigned-byte 8)`

. Since Python does
understand these integer types, it is preferable to use the more
restrictive type, as it allows better type inference
(see operation-type-inference.)

The small, efficient fixnum is contrasted with bignum, or “BIG NUMber”. This is another descriptor representation for integers, but this time a pointer representation that allows for arbitrarily large integers. Bignum operations are less efficient than fixnum operations, both because of the consing and memory reference overheads of a pointer descriptor, and also because of the inherent complexity of extended precision arithmetic. While fixnum operations can often be done with a single instruction, bignum operations are so complex that they are always done using generic arithmetic.

A crucial point is that the compiler will use generic arithmetic if it
can’t `prove` that all the arguments, intermediate values, and
results are fixnums. With bounded integer types such as
`fixnum`

, the result type proves to be especially problematical,
since these types are not closed under common arithmetic operations
such as `+`

, `-`

, `*`

and `/`

. For example,
`(1+ (the fixnum x))`

does not necessarily evaluate to a
`fixnum`

. Bignums were added to Common Lisp to get around this
problem, but they really just transform the correctness problem “if
this add overflows, you will get the wrong answer” to the efficiency
problem “if this add `might` overflow then your program will run
slowly (because of generic arithmetic.)”

There is just no getting around the fact that the hardware only
directly supports short integers. To get the most efficient open
coding, the compiler must be able to prove that the result is a good
integer type. This is an argument in favor of using more restrictive
integer types: `(1+ (the fixnum x))`

may not always be a
`fixnum`

, but `(1+ (the (unsigned-byte 8) x))`

always
is. Of course, you can also assert the result type by putting in lots
of `the`

declarations and then compiling with `safety`

`0`

.

Next: Word Integers, Previous: Generic Arithmetic, Up: Numbers [Contents][Index]