Common Lisp the Language, 2nd Edition

Next: Logical Operations on Up: Numbers Previous: Branch CutsPrincipal

# 12.6. Type Conversions and Component Extractions on Numbers

While most arithmetic functions will operate on any kind of number, coercing types if necessary, the following functions are provided to allow specific conversions of data types to be forced when desired.

[Function]
`float number &optional other`

This converts any non-complex number to a floating-point number. With no second argument, if number is already a floating-point number, then number is returned; otherwise a `single-float` is produced. If the argument other is provided, then it must be a floating-point number, and number is converted to the same format as other. See also `coerce`.

[Function]
`rational number
``rationalize number`

Each of these functions converts any non-complex number to a rational number. If the argument is already rational, it is returned. The two functions differ in their treatment of floating-point numbers.

`rational` assumes that the floating-point number is completely accurate and returns a rational number mathematically equal to the precise value of the floating-point number.

`rationalize` assumes that the floating-point number is accurate only to the precision of the floating-point representation and may return any rational number for which the floating-point number is the best available approximation of its format; in doing this it attempts to keep both numerator and denominator small.

It is always the case that

    (float (rational x) x) == x

and

    (float (rationalize x) x) == x

That is, rationalizing a floating-point number by either method and then converting it back to a floating-point number of the same format produces the original number. What distinguishes the two functions is that `rational` typically has a simple, inexpensive implementation, whereas `rationalize` goes to more trouble to produce a result that is more pleasant to view and simpler to compute with for some purposes.

[Function]
`numerator rational
``denominator rational`

These functions take a rational number (an integer or ratio) and return as an integer the numerator or denominator of the canonical reduced form of the rational. The numerator of an integer is that integer; the denominator of an integer is `1`. Note that

    (gcd (numerator x) (denominator x)) => 1

The denominator will always be a strictly positive integer; the numerator may be any integer. For example:

    (numerator (/ 8 -6)) => -4
    (denominator (/ 8 -6)) => 3

There is no `fix` function in Common Lisp because there are several interesting ways to convert non-integral values to integers. These are provided by the functions below, which perform not only type conversion but also some non-trivial calculations as well.

[Function]
`floor number &optional divisor
``ceiling number &optional divisor
``truncate number &optional divisor
``round number &optional divisor`

In the simple one-argument case, each of these functions converts its argument number (which must not be complex) to an integer. If the argument is already an integer, it is returned directly. If the argument is a ratio or floating-point number, the functions use different algorithms for the conversion.

`floor` converts its argument by truncating toward negative infinity; that is, the result is the largest integer that is not larger than the argument.

`ceiling` converts its argument by truncating toward positive infinity; that is, the result is the smallest integer that is not smaller than the argument.

`truncate` converts its argument by truncating toward zero; that is, the result is the integer of the same sign as the argument and which has the greatest integral magnitude not greater than that of the argument.

`round` converts its argument by rounding to the nearest integer; if number is exactly halfway between two integers (that is, of the form integer+0.5), then it is rounded to the one that is even (divisible by 2).

The following table shows what the four functions produce when given various arguments.

    Argument    floor       ceiling     truncate    round
    ----------------------------------------------------------
     2.6          2           3           2           3
     2.5          2           3           2           2
     2.4          2           3           2           2
     0.7          0           1           0           1
     0.3          0           1           0           0
    -0.3         -1           0           0           0
    -0.7         -1           0           0          -1
    -2.4         -3          -2          -2          -2
    -2.5         -3          -2          -2          -2
    -2.6         -3          -2          -2          -3
    ----------------------------------------------------------

If a second argument divisor is supplied, then the result is the appropriate type of rounding or truncation applied to the result of dividing the number by the divisor. For example, `(floor 5 2)` == `(floor (/ 5 2))` but is potentially more efficient.

This statement is not entirely accurate; one should instead say that `(values (floor 5 2))` == `(values (floor (/ 5 2)))`, because there is a second value to consider, as discussed below. In other words, the first values returned by the two forms will be the same, but in general the second values will differ. Indeed, we have

    (floor 5 2) => 2 and 1
    (floor (/ 5 2)) => 2 and 1/2

for this example.

The divisor may be any non-complex number.

It is generally accepted that it is an error for the divisor to be zero.

The one-argument case is exactly like the two-argument case where the second argument is `1`.

In other words, the one-argument case returns an integer and fractional part for the number: `(truncate 5.3) => 5.0 and 0.3`, for example.

Each of the functions actually returns two values, whether given one or two arguments. The second result is the remainder and may be obtained using `multiple-value-bind` and related constructs. If any of these functions is given two arguments x and y and produces results q and r, then q y+r=x. The first result q is always an integer. The remainder r is an integer if both arguments are integers, is rational if both arguments are rational, and is floating-point if either argument is floating-point. One consequence is that in the one-argument case the remainder is always a number of the same type as the argument.

When only one argument is given, the two results are exact; the mathematical sum of the two results is always equal to the mathematical value of the argument.

Compatibility note: The names of the functions `floor`, `ceiling`, `truncate`, and `round` are more accurate than names like `fix` that have heretofore been used in various Lisp systems. The names used here are compatible with standard mathematical terminology (and with PL/1, as it happens). In Fortran `ifix` means `truncate`. Algol 68 provides `round` and uses `entier` to mean `floor`. In MacLisp, `fix` and `ifix` both mean `floor` (one is generic, the other flonum-in/fixnum-out). In Interlisp, `fix` means `truncate`. In Lisp Machine Lisp, `fix` means `floor` and `fixr` means `round`. Standard Lisp provides a `fix` function but does not specify precisely what it does. The existing usage of the name `fix` is so confused that it seemed best to avoid it altogether.

The names and definitions given here have recently been adopted by Lisp Machine Lisp, and MacLisp and NIL (New Implementation of Lisp) seem likely to follow suit.

[Function]
`mod number divisor
``rem number divisor`

`mod` performs the operation `floor` on its two arguments and returns the second result of `floor` as its only result. Similarly, `rem` performs the operation `truncate` on its arguments and returns the second result of `truncate` as its only result.

`mod` and `rem` are therefore the usual modulus and remainder functions when applied to two integer arguments. In general, however, the arguments may be integers or floating-point numbers.

    (mod 13 4) => 1                 (rem 13 4) => 1
    (mod -13 4) => 3                (rem -13 4) => -1
    (mod 13 -4) => -3               (rem 13 -4) => 1
    (mod -13 -4) => -1              (rem -13 -4) => -1
    (mod 13.4 1) => 0.4             (rem 13.4 1) => 0.4
    (mod -13.4 1) => 0.6            (rem -13.4 1) => -0.4

Compatibility note: The Interlisp function `remainder` is essentially equivalent to the Common Lisp function `rem`. The MacLisp function `remainder` is like `rem` but accepts only integer arguments.

[Function]
`ffloor number &optional divisor
` `fceiling number &optional divisor
` `ftruncate number &optional divisor
` `fround number &optional divisor`

These functions are just like `floor`, `ceiling`, `truncate`, and `round`, except that the result (the first result of two) is always a floating-point number rather than an integer. It is roughly as if `ffloor` gave its arguments to `floor`, and then applied `float` to the first result before passing them both back. In practice, however, `ffloor` may be implemented much more efficiently. Similar remarks apply to the other three functions. If the first argument is a floating-point number, and the second argument is not a floating-point number of longer format, then the first result will be a floating-point number of the same type as the first argument. For example:

    (ffloor -4.7) => -5.0 and 0.3
    (ffloor 3.5d0) => 3.0d0 and 0.5d0

[Function]
`decode-float float
``scale-float float integer
``float-radix float
``float-sign float1 &optional float2
``float-digits float
``float-precision float
``integer-decode-float float`

The function `decode-float` takes a floating-point number and returns three values.

The first value is a new floating-point number of the same format representing the significand; the second value is an integer representing the exponent; and the third value is a floating-point number of the same format indicating the sign (-1.0 or 1.0). Let b be the radix for the floating-point representation; then `decode-float` divides the argument by an integral power of b so as to bring its value between 1/b (inclusive) and 1 (exclusive) and returns the quotient as the first value. If the argument is zero, however, the result is equal to the absolute value of the argument (that is, if there is a negative zero, its significand is considered to be a positive zero).

The second value of `decode-float` is the integer exponent e to which b must be raised to produce the appropriate power for the division. If the argument is zero, any integer value may be returned, provided that the identity shown below for `scale-float` holds.

The third value of `decode-float` is a floating-point number, of the same format as the argument, whose absolute value is 1 and whose sign matches that of the argument.

The function `scale-float` takes a floating-point number f (not necessarily between 1/b and 1) and an integer k, and returns `(* f (expt (float b f) k))`. (The use of `scale-float` may be much more efficient than using exponentiation and multiplication and avoids intermediate overflow and underflow if the final result is representable.)

Note that

    (multiple-value-bind (signif expon sign)
                         (decode-float f)
      (scale-float signif expon))
    == (abs f)

and

    (multiple-value-bind (signif expon sign)
                         (decode-float f)
      (* (scale-float signif expon) sign))
    == f

The function `float-radix` returns (as an integer) the radix b of the floating-point argument.

The function `float-sign` returns a floating-point number z such that z and float1 have the same sign and also such that z and float2 have the same absolute value. The argument float2 defaults to the value of `(float 1 float1)`; `(float-sign x)` therefore always produces a `1.0` or `-1.0` of appropriate format according to the sign of `x`. (Note that if an implementation has distinct representations for negative zero and positive zero, then `(float-sign -0.0)` => `-1.0`.)

The function `float-digits` returns, as a non-negative integer, the number of radix-b digits used in the representation of its argument (including any implicit digits, such as a ``hidden bit''). The function `float-precision` returns, as a non-negative integer, the number of significant radix-b digits present in the argument; if the argument is (a floating-point) zero, then the result is (an integer) zero. For normalized floating-point numbers, the results of `float-digits` and `float-precision` will be the same, but the precision will be less than the number of representation digits for a denormalized or zero number.

The function `integer-decode-float` is similar to `decode-float` but for its first value returns, as an `integer`, the significand scaled so as to be an integer. For an argument f, this integer will be strictly less than

    (expt b (float-precision f))

but no less than

    (expt b (- (float-precision f) 1))

except that if f is zero, then the integer value will be zero.

The second value bears the same relationship to the first value as for `decode-float`:

    (multiple-value-bind (signif expon sign)
                         (integer-decode-float f)
      (scale-float (float signif f) expon))
    == (abs f)

The third value of `integer-decode-float` will be `1` or `-1`.

Rationale: These functions allow the writing of machine-independent, or at least machine-parameterized, floating-point software of reasonable efficiency.

[Function]
`complex realpart &optional imagpart`

The arguments must be non-complex numbers; a number is returned that has realpart as its real part and imagpart as its imaginary part, possibly converted according to the rule of floating-point contagion (thus both components will be of the same type). If imagpart is not specified, then `(coerce 0 (type-of realpart))` is effectively used. Note that if both the realpart and imagpart are rational and the imagpart is zero, then the result is just the realpart because of the rule of canonical representation for complex rationals. It follows that the result of `complex` is not always a complex number; it may be simply a `rational`.

[Function]
`realpart number
``imagpart number`

These return the real and imaginary parts of a complex number. If number is a non-complex number, then `realpart` returns its argument number and `imagpart` returns `(* 0 number)`, which has the effect that the imaginary part of a rational is `0` and that of a floating-point number is a floating-point zero of the same format.

A clever way to multiply a complex number z by i is to write

    (complex (- (imagpart z)) (realpart z))

instead of `(* z #c(0 1))`. This cleverness is not always gratuitous; it may be of particular importance in the presence of minus zero. For example, if we are using IEEE standard floating-point arithmetic and z=4+0i, the result of the clever expression is -0+4i, a true rotation of z, whereas the result of `(* z #c(0 1))` is likely to be

    (4+0i)(+0+i) = ((4)(+0)-(+0)(1))+((4)(1)+(+0)(+0)i
         = ((+0)-(+0))+((4)+(+0))i = +0+4i

which could land on the wrong side of a branch cut, for example.

Next: Logical Operations on Up: Numbers Previous: Branch CutsPrincipal