Modular arithmetic - SBCL 1.0.31 User Manual
Description: SBCL 1.0.31 User Manual

Next: Global and Always-Bound variables, Previous: Dynamic-extent allocation, Up: Efficiency

### 6.3 Modular arithmetic

Some numeric functions have a property: N lower bits of the result depend only on N lower bits of (all or some) arguments. If the compiler sees an expression of form `(logand` exp mask`)`, where exp is a tree of such “good” functions and mask is known to be of type `(unsigned-byte` w`)`, where w is a “good” width, all intermediate results will be cut to w bits (but it is not done for variables and constants!). This often results in an ability to use simple machine instructions for the functions.

Consider an example.

         (defun i (x y)
           (declare (type (unsigned-byte 32) x y))
           (ldb (byte 32 0) (logxor x (lognot y))))

The result of `(lognot y)` will be negative and of type `(signed-byte 33)`, so a naive implementation on a 32-bit platform is unable to use 32-bit arithmetic here. But modular arithmetic optimizer is able to do it: because the result is cut down to 32 bits, the compiler will replace `logxor` and `lognot` with versions cutting results to 32 bits, and because terminals (here—expressions `x` and `y`) are also of type `(unsigned-byte 32)`, 32-bit machine arithmetic can be used.

As of SBCL 0.8.5 “good” functions are `+`, `-`; `logand`, `logior`, `logxor`, `lognot` and their combinations; and `ash` with the positive second argument. “Good” widths are 32 on HPPA, MIPS, PPC, Sparc and x86 and 64 on Alpha. While it is possible to support smaller widths as well, currently this is not implemented.