REF NUMBERS John Gibson Feb 1995
COPYRIGHT University of Sussex 1995. All Rights Reserved.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< PROCEDURES ON NUMBERS >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
This file describes all the Poplog number types and procedures to
operate on them. For information on the textual representation of
different kinds of numbers in Pop-11 see REF * ITEMISE
All the Poplog arithmetic operations described in this file check
the types of their arguments at run time in order to determine what to
do. Fast, non-checking (hence more efficient) integer operations are
described in REF * FASTPROCS
CONTENTS - (Use <ENTER> g to access required sections)
1 Overview
1.1 Note on Terminology
1.2 Fast integer operations
1.3 Computation on Real Numbers
1.4 Complex Numbers
1.5 Conventions for Formal Parameters of Procedures
2 Predicates Relating to Numbers
3 Comparisons on Numbers
4 Number Representation
5 Arithmetic Operations
6 Rational and Integer Specific Operations
7 Complex Specific Operations
8 Mathematical Functions
9 Trigonometric Functions
10 Bitwise/Logical Integer Operations
11 Random Numbers
12 Floating_Point Utilities
13 Numeric Constants
13.1 Integer
13.2 Floating-Point
14 Miscellaneous
-----------
1 Overview
-----------
From Version 12 of Poplog, support is provided for all the numerical
data types and associated functions specified by the Common LISP
standard. This includes integers, bigintegers, decimals, ddecimals,
ratios and complex numbers.
This REF file describes the Pop-11 interface to these facilities, which,
while differing in some minor respects from the Common LISP standard,
(and of course employing different names for procedures in many cases),
is essentially an upward-compatible version of it. For a description of
the Clisp version see Guy L. Steele, Common LISP: The Language, Chapter
12.
For information on the textual representation of different kinds of
numbers in Pop-11 see REF * ITEMISE
All the Poplog arithmetic operations described in this REF file check
the types of their arguments at run time in order to determine what to
do. Fast, non-checking (hence more efficient) integer operations are
described in REF * FASTPROCS
1.1 Note on Terminology
------------------------
In this document the term 'integer' means either a simple integer or a
biginteger, except where explicitly qualified as one or the other;
'integral' means the same in the nominal sense, or 'integer-valued' as
an adjective. Similarily, 'real' means 'non-complex', or 'non-complex
number' - it does NOT carry the meaning of 'floating-point number' used
by some programming languages.
1.2 Fast integer operations
----------------------------
All Poplog arithmetic operations described below check the types of
their arguments at run time in order to determine what to do. This gives
great flexibility in writing generic procedures, but can mean that
efficiency is sacrificed. As a partial solution fast, non-checking
integer operations are provided. These are described in REF * FASTPROCS
Further information concerning efficiency is available in
HELP * EFFICIENCY
1.3 Computation on Real Numbers
--------------------------------
Overall, the number types in Poplog provide three classes of
representation:
¤ rational (simple integers, bigintegers and ratios)
¤ simple floating-point (decimals)
¤ double-length floating-point (ddecimals)
These classes are orthogonal in the sense that a given real number has
exactly one representation in each format (the representation being
exact for rational, and approximate for floating-point).
In particular for rationals, this implies that integers, bigintegers and
ratios are mutually disjoint in terms of the numbers they represent, and
that no two ratios represent the same number unless they have the same
numerator and denominator. In other words, a ratio is always reduced to
its lowest common terms, by dividing numerator and denominator by their
greatest common divisor; if this makes the denominator equal to 1, the
result is the integer numerator (this is the rule of 'rational
canonicalisation'). Any integral result from a computation will always
produce a simple integer (rather than a biginteger) if it can be so
represented.
With very few exceptions, numerical procedures are 'generic', that is,
will accept any kind of numbers as arguments. For all procedures that
perform a rational-type function (i.e. excluding 'irrational' or
'transcendental' functions like sqrt, log, etc), rational argument(s)
will cause the computation to be done using rational arithmetic, and the
result will be rational. Otherwise, when the function is irrational, or
one or more of the arguments is floating-point, all arguments are
converted to double-length floating-point and the computation performed
with double-float arithmetic (this is the rule of 'floating-point
contagion'). The result will be a floating-point whose actual format
depends on the value of the variable popdprecision (see the description
of this below).
1.4 Complex Numbers
--------------------
Complex numbers always have both real and imaginary parts of the same
representation class, and so may similarily be sub-divided into rational
complex, simple-float-complex and double-float-complex. Aside from those
irrational functions that can produce a complex result from a real
argument (sqrt applied to a negative real, for example), the only way of
constructing complex numbers is with the operators +: and -: ('plus i
times' and 'minus i times'). These obey the same rules as for real
arithmetic: with both arguments rational or rational-complex the result
is a rational-complex; if either argument is floating or float-complex,
the result is a float-complex whose format depends on popdprecision.
The only rider to this is the rule of 'rational-complex
canonicalisation', which prevents the production of a rational-complex
number with a 0 imaginary part. Instead, the result is just the real
part of the number. Note that this does not apply to float-complex
numbers, which can have a 0.0 imaginary part.
Most numerical procedures allow complex or mixed real and complex
arguments. In a similar way to the rational/float distinction for the
real case, computations are done in real arithmetic producing a real
result if all arguments are real, or otherwise all arguments are
converted to complex and the operation performed in complex to give a
complex result (the rule of 'complex contagion').
1.5 Conventions for Formal Parameters of Procedures
----------------------------------------------------
Except in those cases where the arguments or results of a procedure are
sufficiently complicated to require names that describe their function,
rather than just their type, the following conventions are used:
Convention Data type
---------- ---------
item anything
bool a boolean, true or false
num, num1, num2 any number, including complex
real, real1, real2 any number except complex
N a simple integer
int, int1, int2 any integer, simple or big
float, float1, float2 a decimal or ddecimal
---------------------------------
2 Predicates Relating to Numbers
---------------------------------
isinteger(item) -> bool [procedure]
Returns true if item is a simple integer, false otherwise.
isbiginteger(item) -> bool [procedure]
Returns true if item is a biginteger, false otherwise.
isintegral(item) -> bool [procedure]
Returns true if item is a simple integer or a biginteger, false
otherwise.
isratio(item) -> bool [procedure]
Returns true if item is a ratio, false otherwise.
isrational(item) -> bool [procedure]
Returns true if item is a simple integer, a biginteger or a
ratio, and false otherwise.
isdecimal(item) -> bool [procedure]
Returns true if item is a decimal or a ddecimal, false
otherwise.
issdecimal(item) -> bool [procedure]
Returns true if item is a simple decimal, false otherwise.
isddecimal(item) -> bool [procedure]
Returns true if item is a ddecimal, false otherwise.
isreal(item) -> bool [procedure]
Returns true if item is any number except a complex, false
otherwise.
iscomplex(item) -> bool [procedure]
Returns true if item is a complex number, false otherwise.
isnumber(item) -> bool [procedure]
Returns true if item is any kind of number, false otherwise.
-------------------------
3 Comparisons on Numbers
-------------------------
num1 = num2 -> bool [operator 7]
num1 /= num2 -> bool [operator 7]
On numbers, these operators compare their arguments for
mathematical equality and inequality respectively.
Different types of rationals (integers, bigintegers and ratios)
can never represent the same number and so can never be equal;
comparisons between floating-point (decimals and ddecimals) and
between floating-point and rationals first convert both
arguments to double float.
The same rules apply to the comparison of the real and imaginary
parts of a complex numbers. Note that a real number compared
with a complex number will be equal only if the complex number
is a float-complex with 0.0 imaginary part (since the imaginary
part of a rational complex must always be non-zero). See also
REF * DATA, HELP * EQUAL
real1 < real2 -> bool [operator 6]
real1 <= real2 -> bool [operator 6]
real1 > real2 -> bool [operator 6]
real1 >= real2 -> bool [operator 6]
These operators compare their first argument to be respectively
less than, less than or equal, greater than, and greater than or
equal to their second argument, where comparisons between
different number types are performed as for = and /=. Both
arguments must be real numbers.
max(real1, real2) -> greatest [procedure]
min(real1, real2) -> least [procedure]
max returns the greatest of its two arguments and min the least,
where 'greatest' means closest to positive infinity, and 'least'
means closest to negative infinity. Both arguments must be real
numbers.
num1 ==# num2 -> bool [operator 7]
Returns true if num1 and num2 are identical (i.e. ==), or
numbers of the same representational type and numeric value.
Decimals and ddecimals are NOT considered to be of the same
type. Two complex numbers are ==# if their real parts are ==#
and their imaginary parts are ==# .
------------------------
4 Number Representation
------------------------
popdprecision -> bool_or_word [variable]
bool_or_word -> popdprecision
The value of this variable controls the production of results
from floating-point computations, in combination with the types
of the arguments supplied to the relevant procedure. In the
following, "decimal" includes decimal-complex and "ddecimal"
includes ddecimal-complex (when a complex floating-point
operation is involved):
Value Effect
----- ------
false Simple decimal results are always produced.
the word A ddecimal result is produced only if one or
"ddecimal" other (or the only) argument was ddecimal. (This
is the behaviour specified by Common LISP.)
any other Same as the previous case, except that a
ddecimal result is also produced when neither
argument is a simple decimal, i.e. all
argument(s) are ddecimal or rational.
(Note that in NO case is there an increase in precision of
floating point computations if all arguments are simple decimal
to start with.)
The default value of popdprecision is false.
pop_reduce_ratios -> bool [variable]
bool -> pop_reduce_ratios
It was stated above that a ratio result is always reduced to its
lowest common terms (and therefore to an integral result if the
denominator becomes 1). However, in situations where a rational
computation is being performed that involves a number of
intermediate results, the continual reduction of intermediate
values can be time-consuming; this boolean variable is therefore
provided to enable reduction to be turned off (by setting it
false).
Although unreduced ratios will give correct results in
computation, comparisons on them may not do so (e.g. 2/2 will
not come out = to 1), so this facility must be used CAREFULLY:
pop_reduce_ratios should only be set false inside a procedure
that has it as a dynamic local, and you should always ensure
that the variable is returned to true before producing the final
result of a computation.
number_coerce(num1, to_num) -> num2 [procedure]
Produces a number num2 which is the number num1 converted to the
representation class (i.e. rational, simple decimal or
double-float ddecimal) of the number to_num.
Firstly, no new number is constructed unless necessary; thus if
the class of num1 already matches that of to_num, num1 is
returned unchanged. Otherwise, conversion from one class to
another proceeds.
Conversion from rational form to floating-point form, or from
one float format to the other, takes place in the obvious way.
For conversion from floating-point to rational, the float is
assumed to be completely accurate, and a mathematically equal
rational number is returned.
If num1 is complex, then num2 is the complex number got by
applying number_coerce recursively to the real and imaginary
parts of num1, i.e.
number_coerce(realpart(num1), to_num)
+: number_coerce(imagpart(num1), to_num) -> num2
If the second argument to_num is itself complex, then num1 is
coerced to a complex number of the same representation class,
i.e. the result is computed as
realpart(to_num) -> to_num;
number_coerce(realpart(num1), to_num)
+: number_coerce(imagpart(num1), to_num) -> num2
where imagpart will fill in an appropriate zero value for the
imaginary part if num1 is real.
------------------------
5 Arithmetic Operations
------------------------
num1 + num2 -> num3 [operator 5]
num1 - num2 -> num3 [operator 5]
num1 * num2 -> num3 [operator 4]
num1 / num2 -> num3 [operator 4]
These operators respectively add, subtract, multiply and divide
their arguments, which may be any numbers. The type of the
result depends on the rules of floating-point and complex
contagion as described above. In particular, note that dividing
one integer by another produces a ratio when the result is not
exact.
- num1 -> num2 [operator 1]
As a prefix operator, - is equivalent to negate(num1).
divid // divis -> (rem, quot) [operator 4]
divid div divis -> quot [operator 2]
divid rem divis -> rem [operator 2]
The two results returned by the operator // are defined by
intof(divid / divis) -> quot
and
divid - (quot * divis) -> rem
where the arguments may be any numbers, including complex. The
two results may be obtained separately with div (quot only) and
rem (rem only).
divid mod divis -> mod [operator 2]
Returns divid modulo divis, where both numbers must be real.
This is defined as
divid rem divis -> rem;
if (divis > 0 and rem < 0) or (divis < 0 and rem >= 0) then
rem+divis -> mod
else
rem -> mod
endif
(i.e. the result always has the same sign as the divisor).
intof(num) -> int [procedure]
For num real, intof truncates its argument to an integer, i.e.
it returns the integer of the same sign as num and with the
largest magnitude such that abs(int) <= abs(num). For a complex
number, the result is the integral complex number obtained by
applying intof to its parts, i.e.
intof(realpart(num)) +: intof(imagpart(num))
fracof(num) -> frac [procedure]
The fractional part of num, defined as
num - intof(num)
round(num) -> int [procedure]
For num real, rounds num to an integer by taking intof(num+1/2)
if num is positive, or intof(num-1/2) otherwise. If num is
complex, the result is
round(realpart(num)) +: round(imagpart(num))
abs(num) -> real [procedure]
Returns the absolute value of num, which (except for complex)
will always be a number of the same type. For any complex num,
the result will be a floating-point real, computed as
sqrt( realpart(num)**2 + imagpart(num)**2 )
negate(num1) -> num2 [procedure]
Returns the negation of num1, which will always be a number of
the same type.
sign(num) -> sign [procedure]
For num real, sign returns -1, 0 or 1 of the same type as num,
depending on whether num is negative, zero or positive. If num
is complex, the result is a floating-point complex number such
that
abs(sign) = 1.0, phase(sign) = phase(num)
-------------------------------------------
6 Rational and Integer Specific Operations
-------------------------------------------
checkinteger(item, low_int, hi_int) [procedure]
Checks item to be a (simple) integer within the range specified
by lower bound low_int and upper bound hi_int (inclusive).
Either or both bounds may be false to indicate no upper or lower
limit. If all conditions are satisfied the procedure returns
with no action, otherwise a mishap occurs.
(Note that * fi_check is a faster version that does not check
its second and third arguments are integers, and also returns
item if it is an integer within the given range.)
gcd_n(int1, int2, ..., intN, N) -> gcd [procedure]
Computes the greatest common divisor of the all the N integers
int1, int2, ..., intN, where the number N itself (a simple
integer >= 0) appears as the rightmost argument. If N = 0, then
gcd = 0; if N = 1, then gcd = int1.
lcm_n(int1, int2, ..., intN, N) -> lcm [procedure]
Computes the least common multiple of the all the N integers
int1, int2, ..., intN, where the number N itself (a simple
integer >= 0) appears as the rightmost argument. If N = 0, then
lcm = 1; if N = 1, then lcm = int1.
destratio(rat) -> (numerator, denominator) [procedure]
numerator(rat) -> numerator [procedure]
denominator(rat) -> denominator [procedure]
These procedures return the numerator and denominator parts of a
rational number, either together (destratio), or separately
(numerator and denominator). When rat is integral, then
numerator = rat, and denominator = 1.
------------------------------
7 Complex Specific Operations
------------------------------
num1 +: num2 -> num3 [operator 5]
num1 -: num2 -> num3 [operator 5]
These two operators are the basic way of creating complex
numbers. Effectively, they both multiply their second argument
by "i" (the positive square root of -1), and then either add the
result to (+:) or subtract the result from (-:) the first
argument.
+: num1 -> num2 [operator 1]
-: num1 -> num2 [operator 1]
As prefix operators, +: and -: are equivalent to unary_+:(num1)
and unary_-:(num1) respectively.
unary_+:(num1) -> num2 [procedure]
unary_-:(num1) -> num2 [procedure]
Single-argument versions of +: and -:, which multiply their
argument by i and -i respectively.
conjugate(num1) -> num2 [procedure]
Returns the complex conjugate of its argument. The conjugate of
a real number is itself, while for a complex number it is
realpart(num1) -: imagpart(num1)
i.e. a complex number with the same realpart, but negated
imagpart.
destcomplex(num) -> (realpart, imagpart) [procedure]
realpart(num) -> realpart [procedure]
imagpart(num) -> imagpart [procedure]
These procedures return the real and imaginary parts of a
complex number, either together (destcomplex), or separately
(realpart and imagpart). When num is real, then realpart = num,
and a zero of the same type as num is returned for imagpart.
-------------------------
8 Mathematical Functions
-------------------------
The procedures in this section, as well as most of those in the
following section on trigonometric procedures, compute mathematical
functions whose definitions on the complex plane necessitate choices of
branch cuts and principal values. See the section Branch Cuts, Principal
Values and Boundary Conditions in Chapter 12 of Steele for details of
these.
sqrt(num) -> sqrt [procedure]
Returns the (principal) square root of num. This will be a real
floating-point if num is real and non-negative, and a
float-complex otherwise.
log(num) -> log [procedure]
Returns the natural (base e) logarithm of num, which must not be
a zero of any kind. If num is real and non-negative, the result
is a real floating-point. Otherwise, it is the float-complex
number
log(abs(num)) +: phase(num)
log10(num) -> log [procedure]
Returns the base 10 logarithm of num, which must not be a zero
of any kind. Defined as
log(num) / log(10)
exp(num) -> exponent [procedure]
Returns e raised to the power num, where e is the base of
natural logarithms. The result is a floating-point if the
argument is real, or a float-complex otherwise.
base ** power -> exponent [operator 3]
Returns base raised to the power power, where either may be any
numbers (except that base must not be zero if power is zero of
any type other than integer 0).
If power is an integer, the computation is performed by
successively multiplying powers of base; thus if base is
rational, the result will be exact. If power is integer 0, the
result is always a 1 of the same type as base.
Otherwise, if power is not an integer, the result is computed as
exp(power * log(base))
--------------------------
9 Trigonometric Functions
--------------------------
All the procedures in this section take an angle as argument, or return
one as a result. In both cases, the units of the angle (radians or
degrees) are controlled by the boolean variable popradians (this applies
equally when the angle is complex).
The following diagram of the real plane is provided as a visualisation
aid (angles are given in radians):
Quadrant II | Quadrant I
x < 0, y >= 0 | x >= 0, y >= 0
pi/2 < angle <= pi | 0 <= angle <= pi/2
|
|
pi-A | A
\ | /
---------------+--------------
/ | \
-(pi-A) | -A
|
|
Quadrant III | Quadrant IV
x < 0, y < 0 | x >= 0, y < 0
-pi < angle < -pi/2 | -pi/2 <= angle < 0
(The above is particularly useful in relation to arctan2.)
popradians -> bool [variable]
bool -> popradians
This boolean variable specifies whether the angle arguments for
trigonometric procedures such as sin, cos etc are in radians
(true) or degrees (false). Similarily, it controls the units of
angle results produced by procedures like arcsin, arccos, etc.
Note that the default value is false, implying angles in
degrees.
phase(num) -> realangle [procedure]
Returns the complex phase angle of num as a floating-point
quantity. This will be in the range
- pi < realangle <= pi (radians)
- 180 < realangle <= 180 (degrees)
If num is real, then realangle = 0.0. This procedure is defined
as
arctan2(destcomplex(num))
cis(realangle) -> num [procedure]
Returns the float-complex number
cos(realangle) +: sin(realangle)
(the name cis standing for 'cos + i sin'). Note that this is the
same as
exp(+: realangle)
ONLY when popradians is true (because the latter always
interprets realangle in radians).
sin(angle) -> num [procedure]
cos(angle) -> num [procedure]
tan(angle) -> num [procedure]
These procedures compute the sine, cosine and tangent of angle.
The result is a floating-point, or a float-complex if angle is
complex.
arcsin(num) -> angle [procedure]
arccos(num) -> angle [procedure]
arctan(num) -> angle [procedure]
These procedures compute the arcsine, arccosine and arctangent
of num. For num complex, the result is a float-complex. For num
real, it is a real float, except in the case of arcsin and
arccos when abs(num) > 1.
For arctan, it is an error if num = +:1 or -:1.
arctan2(real_x, real_y) -> realangle [procedure]
Computes the arctangent of real_y / real_x, but using the signs
of the two numbers to derive quadrant information. The result is
a floating-point number in the range
- pi < realangle <= pi (radians)
- 180 < realangle <= 180 (degrees)
(see diagram above). When real_x = 0 and real_y = 0 the result
is defined (arbitrarily) to be 0.0.
sinh(angle) -> num [procedure]
cosh(angle) -> num [procedure]
tanh(angle) -> num [procedure]
These procedures compute the hyperbolic sine, hyperbolic cosine
and hyperbolic tangent of angle. The result is a floating-point,
or a float-complex if angle is complex.
arcsinh(num) -> angle [procedure]
arccosh(num) -> angle [procedure]
arctanh(num) -> angle [procedure]
These procedures compute the hyperbolic arcsine, hyperbolic
arccosine and hyperbolic arctangent of num. For num complex, the
result is a float-complex. For num real, the result will be a
real float, except in the following cases:
arccosh: num < 1
arctanh: abs(num) > 1
For arctanh, it is an error if num = 1 or -1.
pi -> float [constant]
This constant is the best ddecimal approximation to "pi", =
3.14159....
--------------------------------------
10 Bitwise/Logical Integer Operations
--------------------------------------
These procedures enable integers to be manipulated as bit patterns
representing two's-complement values, where bit position N has weight
2**N (i.e. bits are numbered from 0 upwards). Note that (conceptually,
at any rate), the sign bit of an integer is extended indefinitely to the
left. Thus everywhere above its most significant bit, a positive integer
has 0 bits and a negative integer has 1 bits.
int1 && int2 -> int3 [operator 4]
The result of this operation is the logical "and" of the
integers int1 and int2, i.e. there is a 1 in the result for each
bit position for which there is a 1 in both int1 and int2.
int1 &&~~ int2 -> int3 [operator 4]
The result of this operation is the logical "and" of int1 and
the logical complement of int2, i.e. there is a 1 in the result
for each bit position for which there is a 1 in int1 and a 0 in
int2. (Same as int1 && (~~int2) -- useful for clearing bits of
int1 set in int2).
int1 || int2 -> int3 [operator 4]
The result of this operation is the logical "inclusive or" of
int1 and int2, i.e. there is a 1 in the result for each bit
position for which there is a 1 in either int1 or int2.
int1 ||/& int2 -> int3 [operator 4]
The result of this operation is the logical "exclusive or" of
int1 and int2, i.e. there is a 1 in the result for each bit
position for which there is a 1 in either int1 or int2 but not
in both.
~~ int1 -> int2 [operator 4]
Produces the logical complement of the integer int1, i.e. there
is a 1 in the result for each bit position for which int1 has 0.
It is always true that
~~ int = -(int + 1)
int1 << N -> int2 [operator 4]
Produces the bit pattern of int1 shifted left by (simple
integer) N positions; a negative value for N produces a right
shift.
int1 >> N -> int2 [operator 4]
Gives the bit pattern of int1 shifted right by (simple integer)
N positions; a negative value for N implies a left shift.
int1 &&/=_0 int2 -> bool [operator 6]
int1 &&=_0 int2 -> bool [operator 6]
These two operators are equivalent to the boolean expressions
int1 && int2 /== 0
int1 && int2 == 0
but are more efficient (and avoid producing intermediate
results).
testbit(int, N) -> bool [procedure]
bool -> testbit(int, N) -> newint
This procedure and its updater enable the testing and setting or
clearing of the bit at position N in the integer int. The base
procedure returns the state of bit N as a boolean value, true
for 1 and false for 0.
The updater (which is somewhat unusual for an updater in that it
returns a result) produces a new integer newint which is int
with bit N set to 1 or cleared to 0 as specified by the input
bool argument (which may in fact be any item, false meaning 0
and anything else meaning 1).
integer_leastbit(int) -> N_or_false [procedure]
Returns the bit position N of the least-significant bit set in
the integer int (equivalently, N is the highest power of 2 by
which int divides exactly). false is returned for int 0.
integer_length(int) -> N [procedure]
Returns the length in bits of int as a two's-complement integer.
That is, N is the smallest integer such that
int < ( 1 << N) if int >= 0
int >= (-1 << N) if int < 0
Put another way: if int is non-negative then the representation
of int as an unsigned integer requires a field of at least N
bits; alternatively, a minimum of N+1 bits are required to
represent int as a signed integer, regardless of its sign.
integer_bitcount(int) -> N [procedure]
Counts the number of 1 or 0 bits in the two's-complement
representation of int. If int is non-negative, N is the number
of 1 bits; if int is negative, it is the number of 0 bits. (Note
that, owing to the sign extension, there are an infinite number
of 0 bits in a non-negative integer or 1 bits in a negative
integer.) It is always the case that
integer_bitcount(int) = integer_bitcount(-(int+1))
integer_field(size, position) -> access_p [procedure]
This procedure is used to create accessing/updating procedures
for sub-bitfields within integers, and provides a more
convenient (and more efficient) way of manipulating such fields
than by masking and shifting with the operators && and >>, etc.
Given a specification of a bitfield in terms of its width in
bits size, and lowest bit position position (both simple
integers), it returns a procedure access_p. When this is applied
to any integer it extracts the binary value represented by bits
position to position+size-1 within the integer (shifting it
right by position bits to align it at bit 0). That is,
access_p(int) -> field_value
If the size argument is > 0, the field is taken to contain
unsigned (positive or zero values) only; if size < 0, then the
field is signed, and upon extraction, the highest bit of the
field is extended as the sign bit of the resulting value (cf the
corresponding convention used by conskey).
The updater of access_p, on the other hand, takes a field value
and an integer, and returns a new integer in which the contents
of the field bits are replaced by the given value (but which has
the same bits everywhere else). That is:
field_value -> access_p(int) -> newint
Note that the updater makes no check on the range of
field_value; bits 0 to size-1 of field_value are masked out,
shifted up, and inserted into the field position (and it is
therefore irrelevant in this context whether the field is signed
or unsigned).
A further feature is that access_p and its updater can be made
to merely mask out or mask in the field bits, without shifting
the value down or up. That is, upon extraction the field value
is left aligned at bit position in the result; the input value
for updating is assumed to be similarily aligned. This is
achieved by supplying a second argument of false to access_p or
its updater, i.e.
access_p(int, false) -> unshifted_field_value
unshifted_field_value -> access_p(int, false) -> newint
Note also that in this case, extraction of a signed field will
NOT cause it to be sign-extended.
------------------
11 Random Numbers
------------------
The value of the variable ranseed is used as the seed for the generation
of random numbers, each random number generated using one or more
successive seed values (depending on the type of the INT_OR_FLOAT
argument to random0 and random). The algorithm used to generate each
successive seed value is
ranseed fi_* 524269 fi_+ 32749 -> ranseed
which (since all current implementations use 30 bits for a simple
integer) produces a result modulo 2**30. This algorithm has a verified
cycle length of 2**30, i.e. it will produce every possible combination
of 30 bits before repeating a number.
random0(int_or_float) -> random [procedure]
Given a strictly-positive integer or floating-point argument,
this procedure generates a random number of the same type, in
the range
0 <= random < int_or_float
where the distribution of random will be approximately uniform.
The value of the variable ranseed is used as the seed for the
generation process, and is replaced with a new seed value
afterwards.
random(int_or_float) -> random [procedure]
Same as random0, except that whenever the latter would return 0
or 0.0, the original argument int_or_float is returned instead.
It can thus be defined as
random0(int_or_float) -> random;
if random = 0 then int_or_float else random endif;
Hence the range of the result is 0 < random <= int_or_float for
a float, or 1 <= random <= int_or_float for an integer.
ranseed -> n_or_false [variable]
n_or_false -> ranseed
This variable is used to hold the next seed for generation of
random numbers by random0 or random, both of which side-effect
it. If set to false, it will be re-initialised to a random
simple integer the next time either procedure is called (by
using sys_real_time). Otherwise, its value must always be a
simple integer.
----------------------------
12 Floating_Point Utilities
----------------------------
The procedures in this section provide the means to manipulate
floating-point numbers, and make possible the writing of
machine-independent floating-point software. Note that none of these
procedures are affected by the value of popdprecision.
float_decode(float, want_int) -> (mantissa, expo, sign) [procedure]
This procedure takes a floating-point number and splits it into
its component parts, i.e. mantissa, exponent and sign.
The exponent expo is always an integer; the boolean argument
want_int controls whether the mantissa mantissa and sign sign
are returned as floats or integers.
sign represents the sign, and is returned either as a float or
an integer. For want_int false, it is 1.0 or -1.0 of the same
type as the argument, and with the same sign (note that sign is
1.0 for 0.0). For want_int true, it is 1 or -1 (1 for 0.0).
Denoting the radix of the floating-point representation by b
(see pop_float_radix below), expo is the integer power of b by
which mantissa must be multiplied to regain the magnitude of the
original number.
mantissa itself is the absolute value of the number with
b ** expo
divided out, and can be returned in one of two ways: If want_int
is false, then mantissa is returned as a float of the same type,
in the range
1/b <= mantissa < 1
Otherwise, mantissa is is returned as an integer, scaled by
b ** float_precision(float)
(that is, so that the least significant digit in the
representation of float is scaled to unity in the result). If P
= float_precision(float) we then have
b ** (P-1) <= mantissa < b ** P
Thus whether the mantissa is returned as a float or an integer,
it will always be the case that
mantissa * (b ** expo) = abs(float)
(Note that this holds also when float = 0.0, since in this case
expo = 0, and mantissa is 0.0 or 0 depending on want_int.)
float_scale(float1, expo) -> float2 [procedure]
This provides a more efficient way of scaling a float by a power
of the floating-point radix 'b' than by using ** (and avoids any
intermediate overflow or underflow that could occur with the
latter). It returns
float1 * (b ** expo)
as a floating-point of the same type. If the final result
overflows or underflows (i.e. the absolute value of the exponent
is too large for the representation), then false is returned.
For example, this procedure can be used in conjunction with
float_sign to put back together a floating-point number
decomposed with float_decode. That is, after
float_decode(float, false) -> (mantissa, expo, sign)
one can use
float_sign(sign, float_scale(mantissa, expo))
to retrieve the original number.
float_sign(sign_float, float1) -> float2 [procedure]
Returns a floating-point number float2 of the same type and
absolute value as float1, but which has the sign of the float
sign_float.
The argument float1 may also be false. In this case, float2 is
returned as a 1.0 or -1.0 of the same type and sign as
sign_float.
float_digits(float) -> digits [procedure]
Returns, as an integer, the number of radix-'b' digits
represented in the floating-point format of the argument. (I.e.
digits has only two possible values, one for decimals and one
for ddecimals. In all current Poplog implementations, b = 2 and
ddecimal digits is 53 or 56; decimal digits is 50 on Alpha OSF
and 22 on other platforms.)
float_precision(float) -> sigdigits [procedure]
Same as float_digits, except that the number of significant
radix-'b' digits in the argument is returned. Since Poplog
floating-point decimals and ddecimals are always normalised,
this will in fact be identical to float_digits(float), with the
single exception that float_precision(0.0) = 0 for either float
type.
---------------------
13 Numeric Constants
---------------------
This section describes constants that define the ranges of numbers
available in various representation classes.
13.1 Integer
-------------
int_parameters [library]
This is a library; to use any of the constants it defines, you
must load it explicitly with
uses int_parameters;
It defines the following parameter constants, all of whose
values relate to the particular implementation of Poplog in use:
pop_max_int [constant]
The largest (i.e. most positive) integer value represented in
immediate format (as an integer).
pop_min_int [constant]
The smallest (i.e. most negative) integer value represented in
immediate format (as an integer).
13.2 Floating-Point
--------------------
float_parameters [library]
This is a library; to use any of the constants it defines, you
must load it explicitly with
uses float_parameters;
It defines the following parameter constants, all of whose
values relate to the particular implementation of Poplog in use:
pop_most_positive_decimal [constant]
The greatest positive value representable in simple decimal
format.
pop_least_positive_decimal [constant]
The smallest positive (non-zero) value representable in
simple decimal format.
pop_least_negative_decimal [constant]
The least negative value (i.e. closest to zero) representable in
simple decimal format.
pop_most_negative_decimal [constant]
The most negative value (i.e. closest to negative infinity)
representable in simple decimal format.
pop_most_positive_ddecimal [constant]
pop_least_positive_ddecimal [constant]
pop_least_negative_ddecimal [constant]
pop_most_negative_ddecimal [constant]
Same as the above for double-length ddecimal format.
pop_plus_epsilon_decimal [constant]
pop_plus_epsilon_ddecimal [constant]
These are the smallest positive numbers in each format which
when added to 1.0 of the same format produce a value not equal
to 1.0. I.e. for each format, the smallest positive e such that
number_coerce(1, e) + e /= 1.0
is true. (N.B. For ddecimal format, this depends on
popdprecision not being false.)
pop_minus_epsilon_decimal [constant]
pop_minus_epsilon_ddecimal [constant]
Same as before, but subtracting from 1.0 instead of adding, i.e.
for each format the smallest positive e such that
number_coerce(1, e) - e /= 1.0
is true.
pop_float_parameters -> fvec [constant]
This is a full vector that holds all the floating-point
constants given above, and which the latter uses to define each
value as a separate constant. You are not advised to use this
directly (since its format may change); always access the values
via LIB * FLOAT_PARAMETERS.
pop_float_radix -> int [constant]
This integer constant is the radix of the floating-point
representation (= 2 in all current Poplog implementations).
-----------------
14 Miscellaneous
-----------------
linearfit(list) -> (m, c) [procedure]
Takes a list of pairs of numbers representing co-ordinates of
points, works out the best straight line through the points, and
returns its slope m, and its Y-intercept c. For vertical or
nearly lines it will produce an error. See LIB * LINEARFIT.
integer_key -> key [constant]
biginteger_key -> key [constant]
ratio_key -> key [constant]
decimal_key -> key [constant]
ddecimal_key -> key [constant]
complex_key -> key [constant]
Structure keys for simple integers, bigintegers, ratios,
decimals, ddecimals and complex numbers (see REF * KEYS).
+-+ C.all/ref/numbers
+-+ Copyright University of Sussex 1995. All rights reserved.