.c
.c
.c
9. Numbers
Lisp Machine Lisp includes several types of numbers, with different
characteristics. Most numeric functions will accept any type of numbers as
arguments and do the right thing. That is to say, they are generic .
In Maclisp, there are generic numeric functions (like plus ) and there
are specific numeric functions (like + ) which only operate on a certain
type. In Lisp Machine Lisp, this distinction does not exist; both function
names exist for compatibility but they are identical. The microprogrammed
structure of the machine makes it possible to have only the generic
functions without loss of efficiency.
The types of numbers in Lisp Machine Lisp are:
fixnum | Fixnums are 24-bit 2's complement binary integers. These are the "preferred,
most efficient" type of number.
|
bignum | Bignums are arbitrary-precision binary integers.
|
flonum | Flonums are floating-point numbers. They have a mantissa of 32 bits and an exponent
of 11 bits, providing a precision of about 9 digits and a range of about 10^300.
Stable rounding is employed.
|
small-flonum | Small flonums are another form of floating-point number, with a mantissa of
18 bits and an exponent of 7 bits, providing a precision of about 5 digits
and a range of about 10^19. Small flonums are useful because, like fixnums,
they don't require any storage. Computing with small flonums is
more efficient than with regular flonums.
|
Numbers are different from other objects in that they don't "have
identity." To put it another way, eq does not work on them.
Numbers do not behave "like objects." Fixnums and small flonums are
exceptions to this rule; some system code knows that eq works on
fixnums used to represent characters or small integers, and uses
memq or assq on them.
The Lisp machine automatically converts between fixnums and bignums
as necessary when computing with integers. That is, if the result
of a computation with fixnums is too large to be represented as a fixnum,
it will be represented as a bignum. If the result of a computation
with bignums is small enough to be represented as a fixnum, it will be.
The Lisp machine never automatically converts between flonums and small
flonums, since this would lead either to inefficiency or to unexpected
numerical inaccuracies. The user controls whether floating-point
calculations are done in large or small precision by the type of the
original input data.
Integer computations cannot "overflow", except for division by zero,
since bignums can be of arbitrary size. Floating-point computations
can get exponent overflow or underflow, if the result is too large or small
to be represented. This will signal an error.
When an arithmetic function of more than one argument is given arguments of
different numeric types, uniform coercion rules are followed to convert
the arguments to a common type, which is also the type of the result (for
functions which return a number). When a fixnum meets a bignum, the result
is (usually) a bignum. When a fixnum or a bignum meets a small flonum or a flonum,
the result is a small flonum or a flonum (respectively). When a small flonum
meets a regular flonum, the result is a regular flonum.
Unlike Maclisp, Lisp Machine Lisp does not have number declarations in the compiler.
Note that because fixnums and small flonums are "inums" (require no associated
storage) they are as efficient as declared numbers in Maclisp.
The different types of numbers are distinguished by their printed
representations. A leading or embedded decimal point, and/or an exponent
separated by "e", indicates a flonum. If a number has an exponent
separated by "s", it is a small flonum. Small flonums require a special
indicator so that naive users will not be accidentally tricked into
computing with the lesser precision. Fixnums and bignums have similar
printed representations; the number is a bignum if it is too big to be a
fixnum.
9.1 Numeric Predicates
zerop
x
Returns t if x is zero. Otherwise it returns nil .
If x is not a number, zerop causes an error.
plusp
x
Returns t if its argument is a positive number, strictly greater
than zero. Otherwise it returns nil .
If x is not a number, plusp causes an error.
minusp
x
Returns t if its argument is a negative number, strictly
less than zero. Otherwise it returns nil .
If x is not a number, minusp causes an error.
oddp
number
Returns t if number is odd, otherwise nil .
If number is not a fixnum or a bignum, oddp causes an error.
evenp
number
Returns t if number is even, otherwise nil .
If number is not a fixnum or a bignum, evenp causes an error.
signp Special Formsignp is used to test the sign of a number. It is present
only for Maclisp compatibility, and is not recommended for use in new
programs.
(signp test x) returns
t if
x is a number
which satisfies the
test ,
nil if it is not.
test is not
evaluated, but
x is.
test can be one of the following:
l | x < 0
|
le | x ≤ 0
|
e | x = 0
|
n | x ≠ 0
|
ge | x ≥ 0
|
g | x > 0
|
Examples:
(signp le 12) => t
(signp n 0) => nil
(signp g 'foo) => nil
See also the data-type predicates fixp , floatp , bigp ,
small-floatp , and numberp (LINK:(fixp-fun)).
All of these functions require that their arguments be numbers, and signal
an error if given a non-number. They work on all types of numbers,
automatically performing any required coercions.
=
x y
Returns t if x and y are numerically equal.
greaterp
x y &rest more-args
greaterp compares its arguments from left to right. If any argument
is not greater than the next,
greaterp returns
nil . But if the
arguments are monotonically strictly decreasing, the result is
t .
Examples:
(greaterp 4 3) => t
(greaterp 4 3 2 1 0) => t
(greaterp 4 3 1 2 0) => nil
>
x y
Returns t if x is strictly greater than y , and nil
otherwise.
>= x y Macro
≥ x y Macro
Returns t if x is greater than or equal to y , and nil
otherwise.
lessp
x y &rest more-args
lessp compares its arguments from left to right. If any argument
is not less than the next,
lessp returns
nil . But if the
arguments are monotonically strictly increasing, the result is
t .
Examples:
(lessp 3 4) => t
(lessp 1 1) => nil
(lessp 0 1 2 3 4) => t
(lessp 0 1 3 2 4) => nil
<
x y
Returns t if x is strictly less than y , and nil
otherwise.
<= x y Macro
≤ x y Macro
Returns t if x is less than or equal to y , and nil
otherwise.
≠ x y MacroReturns t if x is not equal to y , and nil otherwise.
9.2 Arithmetic
All of these functions require that their arguments be numbers, and signal
an error if given a non-number. They work on all types of numbers,
automatically performing any required coercions.
plus
&rest args
+ &rest args
+$ &rest args
Returns the sum of its arguments. If there are no arguments, it returns
0, which is the identity for this operation.
difference
arg &rest args
Returns its first argument minus all of the rest of its arguments.
-
arg &rest args
-$ arg &rest args
With only one argument, - is the same as minus ; it
returns the negative of its argument.
With more than one argument, - is the same as difference ;
it returns its first argument minus all of the rest of its arguments.
times
&rest args
* &rest args
*$ &rest args
Returns the product of its arguments. If there are no arguments, it
returns 1, which is the identity for this operation.
quotient
arg &rest args
Returns the first argument divided by all of the rest of its arguments.
//
arg &rest args
//$ arg &rest args
The name of this function is written
// rather than
/ because
/ is the quoting character in Lisp syntax and must be doubled.
With more than one argument,
// is the same as
quotient ;
it returns the first argument divided by all of the rest of its arguments.
With only one argument,
(// x) is the same as
(// 1 x) .
Examples:
(// 3 2) => 1 ;Fixnum division truncates.
(// 3 2.0) => 1.5
(// 3 2.0s0) => 1.5s0
(// 4 2) => 2
(// 12. 2. 3.) => 2
add1
x
1+ x
1+$ x
(add1 x) is the same as (plus x 1) .
sub1
x
1- x
1-$ x
(sub1 x) is the same as (difference x 1) . Note that the
short name may be confusing: (1- x) does not mean 1-x;
rather, it means x-1.
remainder
x y
\ x y
Returns the remainder of x divided by y .
x and y may not be flonums nor small flonums.
gcd
x y
\\ x y
Returns the greatest common divisor of x and y .
x and y may not be flonums nor small flonums.
expt
x y
^ x y
^$ x y
Returns x raised to the y 'th power. y must be a fixnum.
[I guess this is incompatible with Maclisp.]
exp
x
Returns e raised to the x 'th power, where e is the base of natural logarithms.
log
x
Returns the natural logarithm of x .
sin
x
Returns the sine of x in radians.
sind
x
Returns the sine of x in degrees.
cos
x
Returns the cosine of x in radians.
cosd
x
Returns the cosine of x in degrees.
sqrt
x
Returns the square root of x .
atan
y x
Returns the arctangent of the angle y/x . It always returns a
non-negative number between zero and π/2.
atan2
y x
Returns the arctangent of the angle y/x , except that it returns a
number between -π/2 and π/2.
max
&rest args
max returns the largest of its arguments.
Example:
(max 1 3 2) => 3
max requires at least one argument.
min
&rest args
min returns the smallest of its arguments.
Example:
(min 1 3 2) => 1
min requires at least one argument.
abs
x
Returns
|x| , the absolute value of the number
x .
abs could have been defined by:
(defun abs (x)
(cond ((minusp x) (minus x))
(t x)))
minus
x
Returns the negative of
x .
Examples:
(minus 1) => -1
(minus -3) => 3
*dif
x y
*plus x y
*quo x y
*times x y
These are the internal micro-coded arithmetic functions. There is no
reason why anyone should need to refer to these explicitly, since the
compiler knows how to generate the appropriate code for plus ,
+ , etc. These names are only here for Maclisp compatibility.
The following functions are provided to allow specific conversions of data
types to be forced, when desired.
fix
x
Converts x from a flonum (or small-flonum) to an integer, by truncation.
The result is a fixnum or a bignum as appropriate. If x is already
a fixnum or a bignum, it is returned unchanged.
fixr
x
Converts x from a flonum (or small-flonum) to an integer, by truncation.
float
x
Converts x to a flonum. x may be a fixnum, a bignum, a small-flonum,
or a flonum.
small-float
x
Converts x to a small flonum. x may be a fixnum, a bignum, a small-flonum,
or a flonum.
9.3 Random Functions
random
&optional arg (array si:random-array )
(random) returns a random fixnum, positive or negative.
If arg is present, a fixnum between 0 and arg -1 inclusive is returned.
If array is present, the given array is used instead of the default
one (see below).
[The random algorithm should be described.]
si:random-create-array
size offset seed &optional (area default-array-area )
Creates, initializes and returns a random-number-generator array.
This is used for more advanced applications of the pseudo-random
number generator, in which it is desirable to have several different
controllable resettable sources of random numbers. For the exact
meaning of the arguments, read the code.
size is the size of the array, offset is an integer less than
size , seed is a fixnum.
This calls si:random-initialize on the random array before returning it.
si:random-initialize
array
array must be a random-number-generator array, such as
is created by si:random-create-array . It reinitializes the
contents of the array from the seed (calling random changes
the contents of the array and the pointers, but not the seed).
si:random-array Variable
The value of
si:random-array is the default random-number-generator array.
It is created if
random is called and
si:random-array is unbound.
A random-number-generator array has a leader which is a structure with
the following elements:
3
si:random-fill-pointer | |
| The fill-pointer, the length of the array.
|
si:random-seed | The seed from which to initialize the contents.
|
si:random-pointer-1 | |
| The first pointer.
|
si:random-pointer-2 | |
| The second pointer.
|
9.4 Logical Operations on Numbers
Except for lsh and rot , these functions operate on either
fixnums or bignums. lsh and rot have an inherent word-length
limitation and hence only operate on 24-bit fixnums. Negative numbers
are operated on in their 2's-complement representation. (Negative
numbers used to be disallowed in some cases.)
logior
&rest args
Returns the bit-wise logical
inclusive or of its arguments.
A minimum of one argument is required.
Example:
(logior 4002 67) => 4067
logxor
&rest args
Returns the bit-wise logical
exclusive or of its arguments.
A minimum of one argument is required.
Example:
(logxor 2531 7777) => 5246
logand
&rest args
Returns the bit-wise logical
and of its arguments.
A minimum of one argument is required.
Examples:
(logand 3456 707) => 406
(logand 3456 -100) => 3400
boole
fn &rest args
boole is the generalization of
logand ,
logior , and
logxor .
fn should be a fixnum between 0 and 17 octal inclusive;
it controls the function which is computed. If the binary representation
of
fn is
abcd (
a is the most significant bit,
d the least)
then the truth table for the Boolean operation is as follows:
.sp
y
| 0 1
---------
0| a c
x |
1| b d
If
boole has more than three arguments, it is associated left
to right; thus,
(boole fn x y z) = (boole fn (boole fn x y) z)
With two arguments, the result of
boole is simply its second argument.
A minimum of two arguments is required.
Examples:
(boole 1 x y) = (logand x y)
(boole 6 x y) = (logxor x y)
logand ,
logior , and
logxor are usually preferred over
boole .
bit-test
x y
bit-test is a predicate which returns
t if any of
the bits designated by the 1's in
x are 1's in
y .
bit-test is implemented as a macro which expands as follows:
(bit-test x y ) ==> (not (zerop (logand x y )))
ldb-test
ppss y
ldb-test is a predicate which returns
t if any of
the bits designated by the byte specifier
ppss are 1's in
y .
That is, it returns
t if the designated field is non-zero.
ldb-test is implemented as a macro which expands as follows:
(ldb-test ppss y ) ==> (not (zerop (ldb ppss y )))
lsh
x y
Returns
x shifted left
y bits if
y is positive or zero,
or
x shifted right
|y| bits if
y is negative.
Zero bits are shifted in (at either end) to fill unused positions.
x and
y must be fixnums.
Examples:
(lsh 4 1) => 10 ;(octal)
(lsh 14 -2) => 3
(lsh -1 1) => -2
ash
x y
Shifts x arithmetically left y bits, or right -y bits,
depending on the sign of y . x may be a fixnum or a bignum.
The sign of the result is always the same as the sign of x .
rot
x y
Returns
x rotated left
y bits if
y is positive or zero,
or
x rotated right
|y| bits if
y is negative.
The rotation considers
x as a 24-bit number (unlike Maclisp,
which considers
x to be a 36-bit number in both the pdp-10
and Multics implementations).
x and
y must be fixnums.
Examples:
(rot 1 2) => 4
(rot 1 -2) => 20000000
(rot -1 7) => -1
(rot 15 24.) => 15
haipart
x n
Returns the high n bits of the binary representation of |x| ,
or the low |n| bits if n is negative.
x may be a fixnum or a bignum; note that if x is negative
its absolute value is used.
haulong
x
This returns the number of significant bits in
x .
x may be a fixnum or a bignum.
The result does not depend on the sign of
x .
The result is the least integer not less than the base-2 logarithm of
|x|+1 .
Examples:
(haulong 0) => 0
(haulong 3) => 2
(haulong -7) => 3
9.5 Byte Manipulation Functions
Several functions are provided for dealing with an arbitrary-width field of
contiguous bits appearing anywhere in an integer (a fixnum or a bignum).
Such a contiguous set of bits is called a byte . Note that
we are not using the term byte to mean eight bits, but rather
any number of bits within a number.
These functions use numbers called byte specifiers to
designate a specific byte position within any word. Byte specifiers are fixnums
whose two lowest octal digits represent the size of the
byte, and whose higher (usually two, but sometimes more)
octal digits represent the position
of the byte within a number, counting from the right in bits. A position
of zero means that the byte is at the right end of the number.
For example, the byte-specifier 0010 (i.e., 10 octal) refers to the lowest
eight bits of a word, and the byte-specifier 1010 refers to the next eight
bits. These byte-specifiers will be stylized below as ppss .
The maximum value of the ss digits is 27 (octal), since a byte must
fit in a fixnum although bytes can be loaded from and deposited into bignums.
(Bytes are always positive numbers.)
The format of byte-specifiers is taken from the pdp-10 byte instructions.
ldb
ppss num
ppss specifies a byte of
num , which is returned as a number,
right-justified. The
ss bits of the byte starting at bit
pp
are the lowest
ss bits in the returned value, and the rest of the
bits in the returned value are zero. The name of the function,
ldb , means "load byte".
num may be a fixnum or a bignum.
Example:
(ldb 0306 4567) => 56
mask-field
ppss num
This is similar to
ldb ; however, the specified byte
of
num is returned as a number in position
pp of
the returned word, instead of position 0 as with
ldb .
num must be a fixnum.
Example:
(mask-field 0306 4567) => 560
dpb
byte ppss num
Returns a number which is the same as
num except in the
bits specified by
ppss . The low
ss bits of
byte are placed in those bits.
byte is interpreted as
being right-justified, as if it were the result of
ldb .
num may be a fixnum or a bignum.
Example:
(dpb 23 0306 4567) => 4237
deposit-field
byte ppss num
This is like
dpb , except that
byte is not taken to
be left-justified; the
ppss bits of
byte are used
for the
ppss bits of the result, with the rest of the
bits taken from
num .
num must be a fixnum.
Example:
(deposit-field 230 0306 4567) => 4237
%logldb
ppss fixnum
%logldb is like ldb except that it only loads out of fixnums and
allows a byte size of 30 (octal), i.e. the whole fixnum.
%logdpb
byte ppss fixnum
%logdpb is like dpb except that it only deposits into fixnums.
Using this to change the sign-bit will leave the result as a fixnum,
while dpb would produce a bignum result for arithmetic correctness.
%logdpb is good for manipulating fixnum bit-masks such as are used
in some internal system tables and data-structures.
9.6 24-Bit Numbers
Sometimes it is desirable to have a form of arithmetic which has no
overflow checking (which would produce bignums),
and truncates results to the word size of the machine.
In Lisp Machine Lisp, this is provided by the following set of functions.
Their answers are only correct modulo 2^24.
These functions should not be used for "efficiency";
they are probably less efficient than the functions which do check for
overflow. They are intended for algorithms which require this sort of
arithmetic, such as hash functions and pseudo-random number generation.
%24-bit-plus
x y
Returns the sum of x and y modulo 2^24. Both arguments should
be fixnums.
%24-bit-difference
x y
Returns the difference of x and y modulo 2^24. Both arguments should
be fixnums.
%24-bit-times
x y
Returns the product of x and y modulo 2^24. Both arguments should
be fixnums.
9.7 Double-Precision Arithmetic
These peculiar functions are useful in programs that don't want to use
bignums for one reason or another.
%multiply-fractions
num1 num2
Returns bits 24 through 46 (the most significant half)
of the product of num1 and num2 .
If you call this and %24-bit-times on the same arguments num1
and num2 , regarding them as integers, you can combine
the results into a double-precision product.
If num1 and num2 are regarded as fractions, -1 ≤ num < 1 ,
%multiply-fractions returns 1/2 of their correct product as a fraction.
(The name of this function isn't too great.)
%divide-double
dividend[24:46] dividend[0:23] divisor
Divides the double-precision number given by the first two
arguments by the third argument, and returns the single-precision
quotient. Causes an error if division by zero or if the quotient won't
fit in single precision.
%remainder-double
dividend[24:46] dividend[0:23] divisor
Divides the double-precision number given by the first two
arguments by the third argument, and returns the
remainder. Causes an error if division by zero.
%float-double
high24 low24
high24 and low24 , which must be fixnums, are concatenated
to produce a 48-bit unsigned positive integer. A flonum containing the
same value is constructed and returned. Note that only the 31 most-significant
bits are retained (after removal of leading zeroes.) This function is
mainly for the benefit of read .