Extended Arithmetic Functions
(ExtMath Version 1.0)
by
Dale Koepp

INTRODUCTION

ExtMath is a shareware library of C callable functions for arithmetic
with very large numbers, for 386 and higher PCs.  The normal C integer
types, such as unsigned long, limit applications to four bytes and allow
values up to just over four billion.  (This can be extended to more
bytes using floating point numbers.)  However, the ExtMath library effi-
ciently handles positive integers up to 64K bytes long, and in some
cases longer.  In addition, it includes some useful functions such as
random number generation, greatest common divisor, modular inverse, and
more.

Arithmetic with very large numbers can be useful for a variety of appli-
cations, such as calculating mathematical constants (like pi) to a large
number digits, do-it-yourself cryptography, and so forth.

A great deal of effort went into making these functions run as fast as
possible, both for very large numbers (thousands of bytes long) and
moderately large numbers (such as 64 bytes long).  For example, on a
486/50 processor  it can multiply a 10,000 byte number times another
10,000 byte number in less than one second.  ExtMath does this partly by
taking full advantage of the 32 bit integer instructions on 386 and
higher processors, using tight assembly language programming. (It will
not run on 286 and lower processors.)  It also uses advanced multiply
techniques described later in this document.  (At this time, it does
not use the floating point processor.  Whether doing so would make the
functions even faster remains to be seen.)

This library was compiled using the "large" memory model.  All addresses
are far pointers.

NUMBER FORMAT

The ExtMath functions reference large numbers simply as arrays of type
unsigned long.  Since the IBM PC convention for numbers is lowest order
first (sometimes called "little endian"), this same convention is used
here.  That is, if an array X represents a large number, X[0] is the
lowest order part of that number.

These large numbers are strictly positive and binary.  That is, every
bit is significant and there is no sign bit.  Operations such as sub-
traction that would result in negative numbers will give the twos-
compliment of that result.  These functions will return enough informa-
tion to the application for it to recognize the result as negative, if
need be.  A single exception to every number being strictly binary is
the output of function ExtToDec, which is a decimal format.

The size of a number is always the number of unsigned long integer
values required to make up that value.  Since an unsigned long is four
bytes long, the size is given as one fourth the length of the number in
bytes.  For example, a number 10,000 bytes long has a size of 2,500.
The valid range of size is 0 to 16,383 (65,532 bytes).  A size of zero
always represents a number with a value of zero.  Calling the functions
with sizes outside this range may give unpredictable results.

MULTIPLY TECHNIQUES

An application can multiply two large numbers together using function
ExtMul or ExtMulAdd.  Many of the other functions (including ExtDiv)
rely on ExtMul and ExtMulAdd for their task, so efficient multiplication
is very important.

When an application calls ExtMul or ExtMulAdd, one of three multiply
techniques will be used, depending on the size of the numbers being
multiplied.  Why three techniques?  It turns out that multiplying two
large numbers is a complicated topic.  The traditional method we learned
in school, where each digit of one number is multiplied by each digit of
the other number, is the fastest and easiest for relatively small num-
bers.  But as the numbers get larger the time required grows quadratic-
ally.  That is, if you double the size of the two numbers it takes four
times as long.  This can make even the tightest assembly code bog down
if the numbers are thousands of bytes long.

Fortunately, methods are known for multiplying that are faster than
quadratic, although they add overhead and complexity.  ExtMath uses the
following three multiply methods.

Method 1	The traditional method we learned in school.  It is
	programmed in assembly and is the fastest for sizes of about 17
	(68 bytes) and less.

Method 2	A recursive method based on splitting each number into
	an upper and lower half and combining them in such a way that
	three multiplies of the parts are required instead of the
	expected four.  This method is described in Knuth's The Art of
	Computer Programming, Vol 2, and is faster than method 1 for
	sizes from about 18 and higher.  This is the simplest faster-
	than-quadradic method, but surprisingly, was not discovered
	until the early 1960s.

Method 3	A recursive polynomial method based on splitting each
	number into four parts and combining them in such a way that
	seven multiplies of the parts are required instead of the
	expected sixteen.  This method is described in Knuth's The Art
	of Computer Programming, Vol 2, and is faster than method 2 for
	sizes greater than about 128.  It is closely related to Method
	2, but much more complex.

There are even more subtle multiply methods known, the best of which
involves performing Fourier transforms on the numbers.  Perhaps this
will be Method 4 of ExtMath at some future time.

These methods are transparent when calling the multiply functions.  How-
ever, the disadvantage of methods 2 and 3 is that they allocate memory
for working space, whereas Method 1 does not.  For this reason, if an
application has limited memory it can turn off those methods by setting
the ExtMulMethod global variable accordingly.

FUNCTION OVERVIEWS

Simple Functions

These functions perform very basic tasks on large numbers.  Many of
these could also be performed using existing functions in the C standard
libraries, but are included here for completeness and consistency.

ExtZero - Sets an entire array to zero.

ExtInc - Increments a large number.

ExtDec - Decrements a large number.

ExtMov - Copies one large number into another large number, zero extend-
ing if necessary.

ExtMovUp - Copies one large number into another large number with zero
extend exactly as ExtMov, except that it copies starting at the top of
the array so an overlapping move to a higher address is possible.

ExtSwap - Swaps the values in two arrays of the same size.

ExtNZLen - Returns the length of a large number, not counting the high
order zeros.

ExtMAlloc - Allocates space using malloc.  Its argument conforms to the
convention of  ExtMath for size definition, and if memory is not avail-
able it uses ExtMath's error processing.

ExtReAlloc - Re-allocates space using realloc.  Its argument conforms to
the convention of  ExtMath for size definition, and if memory is not
available it uses ExtMath's error processing.

Basic Arithmetic Functions with Carry

These are the most basic arithmetic functions in the library.  Each,
with the exception of ExtCmp, has a carry in (or borrow in) as its first
argument and a carry out (or borrow out) as its return value.  This
allows for numbers larger than the 64K byte limit by breaking these num-
bers into segments.  For example, let the arrays X0, X1 and X2 represent
one very large number, and arrays Y0, Y1 and Y2 represent another very
large number in equal length segments.  Then addition might be program-
med as:

carry = ExtAdd(0, X0, n, Y0, n);
carry = ExtAdd(carry, X1, n, Y1, n);
carry = ExtAdd(carry, X2, n, Y2, n);

Taking the twos compliment might be programmed as:

carry = ExtNeg(0, X0, n);
carry = ExtNeg(carry, X1, n);
carry = ExtNeg(carry, X2, n);

Functions ExtDiv1 and ExtShiftR do carries into the top of numbers
rather than the bottom, so their order of calls is reversed.  For
example:

carry = ExtDiv1(0, 100, X2, n);
carry = ExtDiv1(carry, 100, X1, n);
carry = ExtDiv1(carry, 100, X0, n);

Function ExtCmp is a special case, and might be programmed as follows:

if ((cmp = ExtCmp(X2, n, Y2, n)) == 0)
	if ((cmp = ExtCmp(X1, n, Y1, n)) == 0)
		cmp = ExtCmp(X0, n, Y0, n);

Following are the functions with carry:

ExtNeg - Change a large number to its twos-compliment value, or option-
ally to its ones-compliment value.

ExtAdd - Add one large number to a second large number, overwriting the
second number.

ExtSub - Subtract one large number from a second large number, over-
writing the second number.

ExtAddToNeg - Subtract a second large number from the first large num-
ber, overwriting the second number.

ExtMul1 - Multiply a large number by one unsigned long value.

ExtDiv1 - Divide a large number by one unsigned long value.

ExtMod1 - Return the unsigned long remainder of division of a large num-
ber by one unsigned long value, without modifying the large number.

ExtShiftL - Shift a large number left 0 to 31 bits.

ExtShiftR - Shift a large number right 0 to 31 bits.

ExtCmp - Compare two large numbers.

Advanced and Special Purpose Functions

These are the remaining functions of ExtMath.  Most of them depend on
more complex algorithms to perform their tasks.

ExtMul and ExtMulA - Multiply one large number times a second large num-
ber giving a third large number.

ExtMulAdd and ExtMulAddA - Multiply one large number times a second
large number, adding the result to a third large number.

ExtDiv - Divide a large number into a second large number, giving both
the quotient and remainder.

ExtMulMod - Multiply one large number times a second large number
modulus a third large number.

ExtMulMod1 - Multiply one unsigned long integer times a second unsigned
long integer modulus a third unsigned long integer.

ExtPowerMod - Raise a large number to the power of a second large number
modulus a third large number, giving a fourth large number.

ExtGCD - Find the greatest common divisor of two large numbers.

ExtInverse - Find the inverse of a large number modulus a second large
number.  That is, given X and M, find Y such that XY mod M = 1.

ExtRandom - Generate random numbers of any size.

ExtRandomSeed - Seed the random number generator with a number of any
size.

ExtToDec - Convert a large number so that it can be easily printed in
decimal.  That is, convert it to "super digits" base one billion.

FATAL ERROR PROCESSING

There are a small number of fatal errors that can occur in the ExtMath
functions (those written in C).  Normally, when a fatal error occurs it
prints a message to stderr and the application program aborts.  The pos-
sible error messages are:

#	Function: Message
-	-----------------
0	ExtMAlloc: memory overflow!
1	ExtMul: not enough room for product in Z, make nz larger!
2	ExtDiv: divide by zero!
3	ExtDiv: not enough room for quotient in Y, make ny larger!

Message 0 may also occur from ExtReAlloc.

Since the application may want to handle the error differently, it can
set the global variable ExtMathErrorFunc to point to its own error pro-
cessing function.  If this variable is set, that function gets called
rather than printing the message to stderr.  By default, this variable
equals NULL.

Those ExtMath functions written in assembly language do not do error
checking.  (The EXTMATH.H file identifies which functions are C and
which are assembler.)  Generally, the only possible errors that can
occur in these functions are divide errors, invalid memory addresses
and invalid array sizes.  These should not occur if the application is
written correctly.


GLOBAL VARIABLES

void (*ExtMathErrorFunc)(int ierr, char *Msg)

	This variable is a pointer to a function (default NULL) that the
	application may supply if it desires to take control of any
	fatal errors.  If a fatal error occurs in an ExtMath function
	and ExtMathErrorFunc is not NULL, the function pointed to by
	ExtMathErrorFunc gets called rather than writing the message to
	stderr.  When that function returns, ExtMath aborts the applica-
	tion.

	ierr - Error number.  Refer to "Fatal Error Processing" above.

	Msg - Message text.

int ExtFastRandom

	This variable determines how to perform random number genera-
	tion.

	0 - This gives random numbers that are more cryptographically
	secure than the faster method, but is fairly CPU intensive.

	1- (Default) This gives random numbers that should be adequate
	for most applications, and is roughly twelve times faster.

int ExtMulMethod

	This variable indicates which multiply methods ExtMath is
	allowed to use for multiplies.  Refer to "Multiply Techniques"
	above.  The application may want to disallow method 3 or method
	2 and 3 in order to save memory from the heap, since these allo-
	cate working space.  Method 3 requires the most working space.
	Method 1 does not allocate working space from the heap at all.

	This can also be used to validate and compare the multiply
	methods.  For example, try multiplying two very large numbers
	with method 3 and then with method 1 to validate that the pro-
	ducts are equal.

	1 - Allow only method 1 for multiplications.

	2 - Allow method 1 and method 2, but not method 3 for multipli-
	cations.

	3 - (Default) Allow all three methods for multiplications


MACROS

BitsForDigits(N)

	Calculates the number of bits required to express a number con-
	taining N decimal digits.  For example, a ten digit number (up
	to 9,999,999,999) requires 34 bits in binary, so BitsForDigits
	(10) equals 34.

NeededForDec(N)

	Calculates the array size needed by ExtToDec to convert a large
	number to its decimal format (to superdigits base one billion).
	This array size is approximately 7% larger than N, the large
	number's normal size.  For example, if the size of a large num-
	ber is 1000, ExtToDec will require the array to be 1071 long
	integers long so that there will be room for the converted num-
	ber.  Therefore, NeededForDec(1000) equals 1071.


DETAILED ExtMath FUNCTION DESCRIPTIONS

Note:
1)	u_long represents unsigned long.
2)	All sizes are in units of long integers.
3)	"i." indicates an input parameter.
	"o." indicates an output parameter.
	"m." indicates a modified parameter.


int ExtAdd(int Carryin, u_long X[], int nx, u_long Y[], int ny)

	Add the large value in X, plus the carry, to the large value in
	Y, overwriting Y.  If nx > ny, only the first ny portion of X is
	added.

	Carryin - i. Carry in bit value of 0 or 1.  For other values,
	only the bottom bit of the word is used.

	X - i. Array containing a large number.

	nx - i. Size of X.

	Y - m. Array containing the large number being added to.

	ny - i. Size of Y.

	return value - Carry out value, 0 or 1.


int ExtAddToNeg(int Borrowin, u_long X[], int nx, u_long Y[], int ny)

	Subtract large number in Y, plus the borrow, from the large num-
	ber in X, overwriting Y.  If nx > ny, only the first ny portion
	of X is used.

	Borrowin - i. Borrow in bit value of 0 or 1.  For other values,
	only the bottom bit of the word is used.

	X - i. Array containing a large number.

	nx - i. Size of X.

	Y - m. Array containing the large number being negated and then
	added to.

	ny - i. Size of Y.

	return value - Borrow out value, 0 or 1.


int ExtCmp(u_long X[], int nx, u_long Y[], int ny)

	Compare the large value in X with that in Y.

	X - i. Array containing first large number.

	nx - i. Size of X.

	Y - i. Array containing second large number.

	ny - i. Size of Y.

	return value -  1 if X > Y;  0 if X = Y;  -1 if X < Y.


int ExtDec(u_long X[], int nx)

	Decrement the large number contained in X.

	X - m. Array containing a large number to decrement.

	nx - i. Size of X.

	return value -  1 if X = 0 before being decremented;  0 other-
	wise.


void ExtDiv(u_long X[], int nx, u_long Y[], int ny)

	Divide the large value in X into that in Y, putting both the
	quotient and remainder into Y.  Fatal errors occur if  the
	divisor is zero or if the Y array is not large enough to contain
	both the quotient and remainder.  Refer to the section above
	about fatal error processing.

	X - i. Array containing the divisor.

	nx - i. Size of X.

	Y - m. Array containing the dividend.  The remainder is returned
	in Y[0 thru nx-1] and the quotient is returned in Y[nx thru
	ny-1].

	ny - i. Size of Y.


u_long ExtDiv1(u_long Carryin, u_long X, u_long Y[], int ny)

	Divide the large number in Y by the unsigned long value X, over-
	writing Y.

	Carryin - i. Carry in value.  Must be less than X.  The carry is
	effectively appended to the top of Y for the divide.

	X - i. Divisor.

	Y - m. Array containing the dividend.

	ny - i. Size of Y.

	return value - The carry out value, that is, the remainder from
	the divide.


int ExtGCD(u_long X[], int nx, u_long Y[], int ny, u_long GCD[])

	Find the greatest common divisor of the two large numbers in X
	and Y, returning it in GCD.

	X - i. Array containing the first large number.

	nx - i. Size of X.

	Y - i. Array containing the second large number.

	ny - i. Size of Y.

	GCD - o. Array containing the returned greatest common divisor.
	It's size must be large enough to contain the largest possible
	value, that is the minimum of nx and ny.

	return value - Actual size of GCD returned.


int ExtInc(u_long X[], int nx)

	Increment the large number contained in X.

	X - m. Array containing a large number to increment.

	nx - i. Size of X.

	return value - 1 if X = 0 after being incremented;  0 otherwise.


int ExtInverse(u_long X[], int nx, u_long M[], int nm, u_long Y[])

	Find the inverse of a large number modulus a second large num-
	ber.  That is, given X and M, find Y such that XY mod M = 1.

	Note that X and M must be relatively prime to do this.  If they
	are not, the function return is 0, and Y is returned such that
	XY mod M equals the greatest common divisor of X and M.  If the
	application wishes to call ExtInverse and does not know if X and
	M are relatively prime, it is likely best to call it anyway,
	checking the return value for success.

	X - i. Array containing the large number to take the inverse of.

	nx - i. Size of X.

	M - i. Array containing the modulus for the inverse.

	nm - i. Size of M and of Y.

	Y - o. Array to place the value of the inverse into.

	return value -  1 if successful;  0 if X and M were not rela-
	tively prime.

u_long *ExtMAlloc(int N)

	Allocates space using malloc.  Its argument conforms to the con-
	vention of ExtMath for size definition, and if memory is not
	available it uses ExtMath's error processing.

	N - i. Size of array to allocate.

	return value - Pointer to the newly allocated array.


u_long ExtMod1(u_long Carryin, u_long X, u_long Y, int ny)

	Divide the large number in Y by the unsigned long value X.  It
	only returns the remainder from the divide, and does not modify
	the value in Y.

	Carryin - i. Carry in value.  Must be less than X.  The carry is
	effectively appended to the top of Y for the divide.

	X - i. Divisor.

	Y - i. Array containing the dividend.

	ny - i. Size of Y.

	return value - The remainder from the divide.


void ExtMov(u_long X[], int nx, u_long Y[], int ny)
void ExtMovUp(u_long X[], int nx, u_long Y[], int ny)

	Copy a large number from X into Y.  If nx > ny, only the lower
	ny portion of X is copied.  If nx < ny, Y is zero extended.  For
	ExtMov, the X and Y arrays may overlap only if Y is a lower
	address than X.  For ExtMovUp, the X and Y arrays may overlap
	only if Y is a higher address than X.

	X - i. Array containing large number to copy from.

	nx - i. Size of X.

	Y - o. Array to copy into

	ny - i. Size of Y.


void ExtMul(u_long X[], int nx, u_long Y[], int ny, u_long Z, int nz)
void ExtMulA(u_long X[], int nx, u_long Y[], int ny, u_long Z)

	Multiply the large number in X times the large number in Y, put-
	ting the product into Z.  ExtMul implements all of the methods
	described in the "Multiply Methods" section above, and deter-
	mines which method to use.  It also does some optimization on
	the numbers, such as checking for leading zeros, before doing
	the multiply.  ExtMulA is the direct call to the assembly
	routine for Method 1, so it avoids this overhead and is perhaps
	more efficient than ExtMul when nx is less than 18.

	It is recommended, but not necessary, that if the X and Y arrays
	are not the same size, to make X the shorter one.

	X - i. Array containing the multiplier.

	nx - i. Size of X.

	Y - i. Array containing the multiplicand.

	ny - i. Size of Y.

	Z - o. Array to put the product into.  This must not be over-
	lapping with X or Y.  For ExtMulA, the size of Z is assumed to
	be (nx + ny).

	nz - i. (ExtMul only) Size of Z.  nz must be greater or equal to
	(nx + ny).


u_long ExtMul1(u_long Carryin, u_long X, u_long Y[], int ny)

	Multiply the unsigned long value in X times the large number in
	Y, adding Carryin to the product, and overwriting Y.

	Carryin - i. Carry in value to add to the product.

	X - i. The multiplier.

	Y - m. Array containing the multiplicand.  Returns containing
	the product.

	ny - i. Size of Y.

	return value - The carry out (overflow) from the multiply.


int ExtMulAdd(u_long X[], int nx, u_long Y[], int ny, u_long Z, int nz)
int ExtMulAddA(u_long X[], int nx, u_long Y[], int ny, u_long Z)

	Multiply the large number in X times the large number in Y,
	adding the product to Z.  ExtMulAdd implements all of the
	methods described in the "Multiply Methods" section above, and
	determines which method to use.  It also does some optimization
	on the numbers, such as checking for leading zeros, before doing
	the multiply.  ExtMulAddA is the direct call to the assembly
	routine for Method 1, so it avoids this overhead and is perhaps
	more efficient than ExtMulAdd when nx is less than 18.

	It is recommended, but not necessary, that if the X and Y arrays
	are not the same size, to make X the shorter one.

	X - i. Array containing the multiplier.

	nx - i. Size of X.

	Y - i. Array containing the multiplicand.

	ny - i. Size of Y.

	Z - m. Array to add the product to.  This must not be overlap-
	ping with X or Y.  For ExtMulAddA, the size of Z is assumed to
	be (nx + ny).

	nz - i. (ExtMulAdd only) Size of Z.  nz must be greater than or
	equal to (nx + ny).

	return value - Carry out (overflow) from the sum of the product
	with Z.  Possible values are 0 and 1.


void ExtMulMod(u_long X[], int nx, u_long Y[], int ny, u_long M[],
               int nm, u_long Z[])

	Calculate the modular product Z = XY mod M.

	X - i. Array containing the multiplier.

	nx - i. Size of X.

	Y - i. Array containing the multiplicand.

	ny - i. Size of Y.

	M - i. Array containing the modulus.

	nm - i. Size of M and of Z.

	Z - o. Array containing the returned modular product.


u_long ExtMulMod1(u_long X, u_long Y, u_long M)

	Calculate the modular product XY mod M.  This may be used
	instead of ExtMulMod when the size of the modulus and numbers
	are one long integer.  It eliminates most of the overhead of
	using ExtMulMod.

	X and Y should each be less than M to prevent a divide error.
	As long as this condition is met, there will be no overflow
	problems.

	X - i. Multiplier

	Y - i. Multiplicand

	M - i. Modulus

	return value - modular product.


int ExtNeg(int Carryin, u_long X[], int nx)

	Change the large number in X to its twos-compliment value, or
	optionally to its ones-compliment value.

	Carryin - i. Carry-in value of 0 or 1.  0 indicates to take
	twos-compliment, 1 indicates to take ones-compliment.

	X - m. Array containing the large number to negate.

	nx - i. Size of X.

	return value -  0 if both Carryin = 0 and X = 0;  1 otherwise.


int ExtNZLen(u_long X[], int nx)

	Returns the length of the large number in X, not counting any
	high order zeros.

	X - i. Array containing a large number.

	nx - i. Size of X.

	return value - New size of X minus the high order zeros in X.
	If the entire value in X is zero, it returns 0.


void ExtPowerMod(u_long X[], int nx, u_long P[], int np, u_long M[],
                 int nm, u_long Z)

	Raise the large number in X to the power in P modulus the number
	in M, putting the result into Z.

	X - i. Array containing a large number.

	nx - i. Size of X.

	P - i. Array containing a large number which is the power.

	np - i. Size of P.

	M - i. Array containing a large number which is the modulus.

	nm - i. Size of M and of Z.

	Z - o. Array into which the result is returned.  Must not over-
	lap arrays X nor P.


void ExtRandom(u_long X[], int nx)

	Generate random numbers of any size.  The application can op-
	tionally seed the random number generator with ExtRandomSeed.
	If not seeded by ExtRandomSeed, a random seed is automatically
	generated from the current date and time, and other semi-random
	system values.

	The global variable ExtFastRandom may be set to 0 or 1 to define
	the random generation method.  A value of 0 is theoretically
	more random, but CPU intensive.  A value of 1 (the default) is
	faster, and satisfactory for most circumstances.

	X - o. Array into which the random number is returned.

	nx - i. Size of X.


void ExtRandomSeed(u_long X[], int nx)

	Seed the random number generator with any number of any size.

	If the value in X is zero, a random seed is automatically gener-
	ated from the current date and time, and other semi-random sys-
	tem values.

	X - i. Array containing the random seed.

	nx - i. Size of X.


u_long *ExtReAlloc(u_long *X, int NewSize)

	Re-allocates space using realloc.  It differs from realloc in
	that the size is in long integers instead of bytes, and if the
	memory is not available it generates an ExtMath fatal error.  If
	the buffer address changes, realloc copies existing data from
	the old buffer to the new buffer, but it does not necessarily
	zero fill the new buffer.

	X - i. Address of a segment of memory previously allocated by
	ExtMAlloc, ExtReAlloc, or one of the standard memory allocation
	functions such as malloc.  X may be NULL.

	NewSize - i. New size of X.  If NewSize = 0, the memory is
	simply released.

	return value - Address of the new buffer.  It may or may not be
	the same as X.  Returns NULL if NewSize = 0.


u_long ExtShiftL(u_long Carryin, int NShift, u_long X[], int nx)

	Shift the large number left 0 to 31 bits, adding Carryin into
	the lower portion after shifting.

	Carryin - i. The carry in value.  Only the lower NShift bits are
	significant, and these are added to the value in X after shift-
	ing.

	NShift - i. The number of bits to shift.  If NShift = 0, the
	function does nothing.

	X - m. Array containing the value to be shifted left.

	nx - i. Size of X.

	return value - Carry out (overflow) from the shift left.


u_long ExtShiftR(u_long Carryin, int NShift, u_long X[], int nx)

	Shift the large number in X right 0 to 31 bits, shifting Carryin
	into the top portion of X.

	Carryin - i. The carry in value.  Only the lower NShift bits are
	significant, and these are shifted into the top portion of X.

	NShift - i. The number of bits to shift.  If NShift = 0, the
	function does nothing.

	X - m. Array containing the value to be shifted right.

	nx - i. Size of X.

	return value - Carry out (remainder) from the shift right.


int ExtSub(int Borrowin, u_long X[], int nx, u_long Y[], int ny)

	Subtract the large value in X, plus the borrow, from that in Y,
	overwriting Y.  If nx > ny, only the first ny portion of X is
	subtracted.

	Borrowin - i. Borrow in value of 0 or 1.  For other values, only
	the bottom bit of the word is used.

	X - i. Array containing a large number.

	nx - i. Size of X.

	Y - m. Array containing the large number being subtracted from.

	ny - i. Size of Y.

	return value - Borrow out value, 0 or 1.  Returns 1 if X plus
	Borrowin is greater than Y, and returns 0 otherwise.


void ExtSwap(u_long X[], u_long Y[], int n)

	Swaps the values in two arrays of the same size.

	X - m. Array containing a large number.

	Y - m. Array containing a large number.

	n - i. Size of X and of Y.


void ExtToDec(u_long X[], int nx)

	Convert the large number in X so that it can be easily printed
	in decimal.  That is, convert it to "super digits" base one bil-
	lion.  Each long integer in the X array will contain a value
	from 0 through 999,999,999 after the conversion.

	In order to contain the full converted value in this format, the
	X array needs to be approximately 7% longer than it would norm-
	ally require.  This length can be determined using the
	NeededForDec macro.

	X - m. Array containing the large number to convert.  It should
	be long enough to contain the result after conversion.  If it is
	not long enough, the program will probably abort with a divide
	error.

	nx - i. Size of X.


void ExtZero(u_long X[], int nx)

	Sets an entire array to zero.

	X - o. Array to set to all zero.
 
	nx - i. Size of X.


REGISTRATION

And now for a little legalese:

	This library is shareware.  This means it is meant to be shared,
	so pass it on to whomever might be interested.

	It also means that if you find it useful for personal not-for-
	profit use, registration is optional but appreciated.

	However, ExtMath is not to be sold by itself or as part of
	another library.  If it is used in an application that is sold
	for profit or used commercially, I must insist on commercial
	registration.

[e-mail address DaleKoepp@AOL.COM]

Registration form:
------------------------------------------------------------------------

ExtMath Registration

Name____________________________________________________________________

Company_________________________________________________________________

Address_________________________________________________________________

	________________________________________________________________

	________________________________________________________________

Amount enclosed:

___ Personal not-for-profit registration	-- $15

___ Commercial registration			-- $50

Comments________________________________________________________________

	________________________________________________________________

Please mail to:

Dale Koepp
P.O. Box 50321
Colorado Springs, CO  80949-0321
