12.2. Number Concepts
Prev | Chapter 12. Numbers | Next

## 12.2. Number Concepts [sec_12-1]

### 12.2.1. Numeric Operations [sec_12-1-1]

#### 12.2.1.1. Additional Integer Functions

Function `EXT:!` `(`EXT:!` `n`)` returns the factorial of `n`, `n` being a nonnegative `INTEGER`.

Function `EXT:EXQUO`. `(`EXT:EXQUO` `x` `y`)` returns the integer quotient `x/y` of two integers `x`,`y`, and `SIGNAL`s an `ERROR` when the quotient is not integer. (This is more efficient than `/`.)

Function `EXT:XGCD`. `(`EXT:XGCD` `x1` ... `xn`)` returns the values `l`, `k1`, ..., `kn`, where `l` is the greatest common divisor of the integers `x1`, ..., `xn`, and `k1`, ..., `kn` are the integer coefficients such that

    l = (GCD x1 ... xn)
      = (+ (* k1 x1) ... (* kn xn))

Function `EXT:MOD-EXPT`. `(`EXT:MOD-EXPT` `k` `l` `m`)` is equivalent to `(`MOD` (`EXPT` `k` `l`) `m`)` except it is more efficient for very large arguments.

#### 12.2.1.2. Function `DECODE-FLOAT`

`FLOAT-RADIX` always returns 2.

`(`FLOAT-DIGITS` `number` `digits`)` coerces `number` (a `REAL`) to a floating point number with at least `digits` mantissa digits. The following always evaluates to `T`:

    (>= (FLOAT-DIGITS (FLOAT-DIGITS number digits)) digits)

#### 12.2.1.3. Boolean Operations [convar_boole-_cm_boole-xor]

Table 12.1. Boolean operations

constant | value
--- | ---
`BOOLE-CLR` | 0
`BOOLE-SET` | 15
`BOOLE-1` | 10
`BOOLE-2` | 12
`BOOLE-C1` | 5
`BOOLE-C2` | 3
`BOOLE-AND` | 8
`BOOLE-IOR` | 14
`BOOLE-XOR` | 6
`BOOLE-EQV` | 9
`BOOLE-NAND` | 7
`BOOLE-NOR` | 1
`BOOLE-ANDC1` | 4
`BOOLE-ANDC2` | 2
`BOOLE-ORC1` | 13
`BOOLE-ORC2` | 11

#### 12.2.1.4. Byte Operations on Integers [sec_12-1-1-3-2]

Byte specifiers are objects of built-in type BYTE, not `INTEGER`s.

#### 12.2.1.5. Floating Point Arithmetics

Function `EXPT`. `(`EXPT` `base` `exponent`)` is not very precise if `exponent` has a large absolute value.

Function `LOG`. `(`LOG` `number` `base`)` `SIGNAL`s an `ERROR` if ``base` = 1`.

Constant `PI`. The value of `PI` is a `LONG-FLOAT` with the precision given by `(`EXT:LONG-FLOAT-DIGITS`)`. When this precision is changed, the value of `PI` is automatically recomputed. Therefore `PI` is not a constant variable.

Function `UPGRADED-COMPLEX-PART-TYPE`. When the argument is not a recognizable subtype or `REAL`, `UPGRADED-COMPLEX-PART-TYPE` `SIGNAL`s an `ERROR`, otherwise it returns its argument (even though a `COMPLEX` number in CLISP can always have `REALPART` and `IMAGPART` of any type) because it allows the most precise type inference.

Variable `CUSTOM:*DEFAULT-FLOAT-FORMAT*`. When rational numbers are to be converted to floats (due to `FLOAT`, `COERCE`, `SQRT` or a transcendental function), the result type is given by the variable `CUSTOM:*DEFAULT-FLOAT-FORMAT*`.

Macro `EXT:WITHOUT-FLOATING-POINT-UNDERFLOW`. The macro `(`EXT:WITHOUT-FLOATING-POINT-UNDERFLOW` {`form`}*)` executes the `form`s, with errors of type `FLOATING-POINT-UNDERFLOW` inhibited. Floating point operations will silently return zero instead of `SIGNAL`ing an `ERROR` of type `FLOATING-POINT-UNDERFLOW`.

Condition `FLOATING-POINT-INVALID-OPERATION`. This `CONDITION` is never `SIGNAL`ed by CLISP.

Condition `FLOATING-POINT-INEXACT`. This `CONDITION` is never `SIGNAL`ed by CLISP.

### 12.2.2. Implementation-Dependent Numeric Constants [sec_12-1-2]

#### 12.2.2.1. Fixnum Limits

Table 12.2. Fixnum limits

CPU type | 32-bit CPU | 64-bit CPU
--- | --- | ---
`MOST-POSITIVE-FIXNUM` | 224-1 = 16777215 | 248-1 = 281474976710655
`MOST-NEGATIVE-FIXNUM` | -224 = -16777216 | -248 = -281474976710656

#### 12.2.2.2. Bignum Limits

`BIGNUM`s are limited in size. Their maximum size is `32*(216-2)=2097088` bits. The largest representable `BIGNUM` is therefore `22097088-1`.

#### 12.2.2.3. Float Limits

Together with `PI`, the other `LONG-FLOAT` constants

`LEAST-NEGATIVE-LONG-FLOAT` | `LONG-FLOAT-EPSILON`
`LEAST-NEGATIVE-NORMALIZED-LONG-FLOAT` | `LONG-FLOAT-NEGATIVE-EPSILON`
`LEAST-POSITIVE-LONG-FLOAT` | `MOST-NEGATIVE-LONG-FLOAT`
`LEAST-POSITIVE-NORMALIZED-LONG-FLOAT` | `MOST-POSITIVE-LONG-FLOAT`

are recomputed whenever `(`EXT:LONG-FLOAT-DIGITS`)` is `SETF`ed. They are not constant variables.

### 12.2.3. Rule of Float Substitutability [sec_12-1-3-3]

When a mathematical function may return an exact (`RATIONAL`) or inexact (`FLOAT`) result, it always returns the exact result.

### 12.2.4. Floating-point Computations [sec_12-1-4]

There are four floating point types: `SHORT-FLOAT`, `SINGLE-FLOAT`, `DOUBLE-FLOAT` and `LONG-FLOAT`:

type | sign | mantissa | exponent | comment
--- | --- | --- | --- | ---
`SHORT-FLOAT` | 1 bit | 16+1 bits | 8 bits | immediate
`SINGLE-FLOAT` | 1 bit | 23+1 bits | 8 bits | IEEE 754
`DOUBLE-FLOAT` | 1 bit | 52+1 bits | 11 bits | IEEE 754
`LONG-FLOAT` | 1 bit | >=64 bits | 32 bits | variable length

The single and double float formats are those of the IEEE 754 “Standard for Binary Floating-Point Arithmetic”, except that CLISP does not support features like `±0`, `±inf`, `NaN`, gradual underflow, etc. Common Lisp does not make use of these features, so, to reduce portability problems, CLISP by design returns the same floating point results on all platforms (CLISP has a floating-point emulation built in for platforms that do not support IEEE 754). Note that

- When you got a `NaN` in your program, your program is broken, so you will spend time determining where the `NaN` came from. It is better to `SIGNAL` an `ERROR` in this case.
- When you got unnormalized floats in your program, your results will have a greatly reduced accuracy anyway. Since CLISP has the means to cope with this - `LONG-FLOAT`s of variable precision - it does not need unnormalized floats.

This is why `*FEATURES*` does not contain the `:IEEE-FLOATING-POINT` keyword.

Arbitrary Precision Floats. `LONG-FLOAT`s have variable mantissa length, which is a multiple of 16 (or 32, depending on the word size of the processor). The default length used when `LONG-FLOAT`s are `READ` is given by the place `(`EXT:LONG-FLOAT-DIGITS`)`. It can be set by `(`SETF` (`EXT:LONG-FLOAT-DIGITS`) `n`)`, where `n` is a positive `INTEGER`. E.g., `(`SETF` (`EXT:LONG-FLOAT-DIGITS`) 3322)` sets the default precision of `LONG-FLOAT`s to about 1000 decimal digits.

#### 12.2.4.1. Rule of Float Precision Contagion [sec_12-1-4-4]

The floating point contagion is controlled by the variable `CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*`. When it is non-`NIL`, contagion is done as per the [ANSI CL standard]: `SHORT-FLOAT` → `SINGLE-FLOAT` → `DOUBLE-FLOAT` → `LONG-FLOAT`.

Rationale:
  See it pragmatically: save what you can and let others worry about the rest.
Brief:
  Common Lisp knows the number's precision, not accuracy, so preserving the precision can be accomplished reliably, while anything relating to the accuracy is just a speculation - only the user (programmer) knows what it is in each case.
Detailed:
  A computer float is an approximation of a real number. One can think of it as a random variable with the mean equal to itself and standard deviation equal to half the last significant digit. E.g., `1.5` is actually `1.5±0.05`. Consider adding `1.5` and `1.75`. [ANSI CL standard] requires that `(`+` 1.5 1.75)` return `3.25`, while traditional CLISP would return `3.3`. The implied random variables are: `3.25±0.005` and `3.3±0.05`. Note that the traditional CLISP way does lie about the mean: the mean is `3.25` and nothing else, while the standard way could be lying about the deviation (accuracy): if the implied accuracy of `1.5 (0.05)` is its actual accuracy, then the accuracy of the result cannot be smaller that that. Therefore, since Common Lisp has no way of knowing the actual accuracy, [ANSI CL standard] (and all the other standard engineering programming languages, like C, Fortran etc) decides that keeping the accuracy correct is the business of the programmer, while the language should preserve what it can - the precision.
Experience:
  Rounding errors accumulate, and if a computation is conducted with insufficient precision, an outright incorrect result can be returned. (E.g., `E(x2) - E(x)2` can be negative!) The user should not mix floats of different precision (that's what `CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*` is for), but one should not be penalized for this too harshly.

When `CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*` is `NIL`, the traditional CLISP method is used, namely the result of an arithmetic operation whose arguments are of different float types is rounded to the float format of the shortest (least precise) of the arguments: `RATIONAL` → `LONG-FLOAT` → `DOUBLE-FLOAT` → `SINGLE-FLOAT` → `SHORT-FLOAT` (in contrast to [sec_12-1-4-4]!)

Rationale:
  See it mathematically. Add intervals: `{1.0 ± 1e-8} + {1.0 ± 1e-16} = {2.0 ± 1e-8}`. So, if we add `1.0s0` and `1.0d0`, we should get `2.0s0`.
Brief:
  Do not suggest accuracy of a result by giving it a precision that is greater than its accuracy.
Example:
  `(`-` (`+` 1.7 `PI`) `PI`)` should not return `1.700000726342836417234L0`, it should return `1.7f0` (or `1.700001f0` if there were rounding errors).
Experience:
  If in a computation using thousands of `SHORT-FLOAT`s, a `LONG-FLOAT` (like `PI`) happens to be used, the long precision should not propagate throughout all the intermediate values. Otherwise, the long result would look precise, but its accuracy is only that of a `SHORT-FLOAT`; furthermore much computation time would be lost by calculating with `LONG-FLOAT`s when only `SHORT-FLOAT`s would be needed.

##### Variable `CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*`

If the variable `CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*` is non-`NIL`, a `WARNING` is emitted for every coercion involving different floating-point types. As explained above, float precision contagion is not a good idea. You can avoid the contagion by doing all your computations with the same floating-point type (and using `FLOAT` to convert all constants, e.g., `PI`, to your preferred type).

This variable helps you eliminate all occurrences of float precision contagion: set it to `T` to have CLISP `SIGNAL` a `WARNING` on float precision contagion; set it to `ERROR` to have CLISP `SIGNAL` an `ERROR` on float precision contagion, so that you can look at the stack backtrace.

#### 12.2.4.2. Rule of Float and Rational Contagion [sec_12-1-4-1]

The contagion between floating point and rational numbers is controlled by the variable `CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*`. When it is non-`NIL`, contagion is done as per the [ANSI CL standard]: `RATIONAL` → `FLOAT`.

When `CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*` is `NIL`, the traditional CLISP method is used, namely if the result is mathematically an exact rational number, this rational number is returned (in contrast to [sec_12-1-4-1]!)

`CUSTOM:*FLOATING-POINT-RATIONAL-CONTAGION-ANSI*` has an effect only in those few cases when the mathematical result is exact although one of the arguments is a floating-point number, such as `(`*` 0 1.618)`, `(`/` 0 1.618)`, `(`ATAN` 0 1.0)`, `(`EXPT` 2.0 0)`, `(`PHASE` 2.718)`.

##### Variable `CUSTOM:*WARN-ON-FLOATING-POINT-RATIONAL-CONTAGION*`

If the variable `CUSTOM:*WARN-ON-FLOATING-POINT-RATIONAL-CONTAGION*` is non-`NIL`, a `WARNING` is emitted for every avoidable coercion from a rational number to a floating-point number. You can avoid such coercions by calling `FLOAT` to convert the particular rational numbers to your preferred floating-point type.

This variable helps you eliminate all occurrences of avoidable coercions to a floating-point number when a rational number result would be possible: set it to `T` to have CLISP `SIGNAL` a `WARNING` in such situations; set it to `ERROR` to have CLISP `SIGNAL` an `ERROR` in such situations, so that you can look at the stack backtrace.

##### Variable `CUSTOM:*PHASE-ANSI*`

A similar variable, `CUSTOM:*PHASE-ANSI*`, controls the return value of `PHASE` when the argument is an exact nonnegative `REAL`. Namely, if `CUSTOM:*PHASE-ANSI*` is non-`NIL`, it returns a floating-point zero; if `CUSTOM:*PHASE-ANSI*` is `NIL`, it returns an exact zero. Example: `(`PHASE` 2/3)`

### 12.2.5. Complex Computations [sec_12-1-5]

Complex numbers can have a real part and an imaginary part of different types. For example, `(`SQRT` -9.0)` evaluates to the number ``#C`(0 3.0)`, which has a real part of exactly `0`, not only `0.0` (which would mean “approximately 0”).

The type specifier for this is `(`COMPLEX` `INTEGER` `SINGLE-FLOAT`)`, and `(`COMPLEX` `type-of-real-part` `type-of-imaginary-part`)` in general.

The type specifier `(`COMPLEX` `type`)` is equivalent to `(`COMPLEX` `type` `type`)`.

### 12.2.6. Rule of Canonical Representation for Complex Rationals [sec_12-1-5-3]

Complex numbers can have a real part and an imaginary part of different types. If the imaginary part is `EQL` to `0`, the number is automatically converted to a real number.

This has the advantage that `(`LET` ((x (`SQRT` -9.0))) (* x x))` - instead of evaluating to ``#C`(-9.0 0.0)`, with `x` = ``#C`(0.0 3.0)` - evaluates to ``#C`(-9.0 0)` = `-9.0`, with `x` = ``#C`(0 3.0)`.

### 12.2.7. Random-State Operations [sec_12-1-7]

To ease reproducibility, the variable `*RANDOM-STATE*` is initialized to the same value on each invocation, so that

    $ clisp -norc -x '(RANDOM 1s0)'

will always print the same number.

If you want a new random state on each invocation, you can arrange for that by using init function:

    $ clisp -norc -x '(EXT:SAVEINITMEM "foo" :init-function (LAMBDA () (SETQ *RANDOM-STATE* (MAKE-RANDOM-STATE T))))'
    $ clisp -norc -M foo.mem -x '(RANDOM 1s0)'

or by placing `(`SETQ` `*RANDOM-STATE*` (`MAKE-RANDOM-STATE` `T`))` into your RC file.

| These notes document CLISP version 2.45 | Last modified: 2008-05-14

Enter your search termsSubmit search form
Webclisp.cons.orgclisp.podval.orgwww.lisp.org

Prev | Up | Next
12.1. Numeric Types | Home | Chapter 13. Characters