.pl 65
.fo ''- % -''
.he 'Todd R. Kueny'4/12/79'Plastic Optics'
.m1 3
.m2 3
.m3 3
.m4 3
.ls 2
.ce 3
Abitrary Length Arithmetic Routines
by Todd R. Kueny
Plastic Optics, Inc.
.sp 4
.ti 8
These routines are designed to handle integers of arbitrary length more
or less efficiently.
The operate in a fashion similar to PDP-11 instructions, that is 
with one source and one destination.
All routines expect values on integer bounderies.
The storage convention is least significant word at the lowest
address.
The routines as given are capable of handling integers of 50 * 16 -1
bits.
If this is not enough, a little editing can expand this to any
unreasonable limit.
.ti 8
The lowest level routines are written in assembler and are the most
efficient.
The _div routine is the least efficient, this is do to a poor divide
algorithym as well as being coded in C.
.ti 8
The routines should contain few suprises and are easy to modify.
The most recently included routine is _lcmpr, if anything goes wrong
it should be the first to suspect.

.ul 1
Arithmetic Shift Right:
.in 8
	Called as _asr(ip, length).  The carry is avialable in the
external int _lcary.  A zero is shifted into the msb.  Length integers
starting at ip are shifted one bit right.
.in 0
.ul 1
Arithmetic Shift Left:
.in 8
	Called as _asl(ip, length).  Similar to _asr except a zero
is shifted into the lsb.

.in 0
.ul 1
Negate:
.in 8
	Called as _neg(ip, length).  The integer at ip is 2's complemented.
The int _lcary contains the resulting carry status.

.in 0
.ul 1
Add:
.in 8
	Called as _add(source, dest, length).  Source is added to dest into
dest.  The carry is available as above.  Overflow is not detected.

.in 0
.ul 1
Subtract:
.in 8
	Called as _sub(source, dest, length).  Source is subtracted from
dest into dest as above.

.in 0
.ul 1
Multiply:
.in 8
	Called as _mul(source, dest, length).  Source is multiplied by
dest into dest.
No upper bits are available with this routine.

.in 0
.ul 1
Divide:
.in 8
	Called as _div(source, dest, length).  Source is divided by
dest into dest.  The remainder is available in _ldivr.

.in 0
.ul 1
String to Binary Conversion:
.in 8
	Called as sconv(astring, ip, length).  Astring may have leading spaces
and an optional minus sign; conversion stops at the first non-numeric
character.  Nothing useful is done on overflow except return erronious results.
The can be avoided by making ip-length large.

.in 0
.ul 1
Binary to String Conversion:
.in 8
	Two routines are available here: locv(ip, length) and 
format(ip, length, abuffer, aformat).
Locv returns a pointer to a static string of digits with an optional
leading minus sign.  Zero is returned as a null string.  Format
converts the integer at ip into a string in abuffer following the 
format in aformat.  The string is garunteed to contain the same
number of characters as the format unless an error is encountered.
In any case, the number of characters in abuffer is returned.
Format accepts $,*,/,_,.,,, ,-,X.  Dollar, star, and space suppress
leading zeros and replace them with themselves.  Comma, dot, and under_score
come out in the same positions as in the format.  The X forces the
digit to be printed.  Minus prints if the number is < 0, otherwise it
comes out as a space.

.in 0
.ul 1
Comparison:
.in 8
	Called as lcmpr(a, stype, b, length).  A and B are integer pointers
to long integers of length length.  Stype is a pointer to a string
which controls the comparision: ">=", "<=", "<", ">", "==", and "!=".
Numbers or letters could be used instead, but the strings improve readablity.
If the condition is true, 1 is returned; otherwise 0.

.in 0
.ul 1
Bugs:
.in 8
	There may be errors in overflow handling by lcmpr.
Care should be in this area.
Otherwise, most everything has been used heavily for at least 6 months
with no difficulty.
If you plan to use more that 30 digits, check sconv and locv, there
buffers will only handle about 30 characters.
