                        Large Number Package for Micro-C

                                     By

                                 Tom St Denis
                                tom@dasoft.org


Introduction
-------------

    LNUM is a complete large number library for Micro-C [*].  It is designed
to be '#include'd into source code directly instead of linked in.  This makes
it very versatile and portable.  Included in this package is the rudimentary
manipulation of large numbers, basic arithmetic, modular arithmetic and a few
number theoretic functions.

    All of the algorithms are optimized fairly well.  Although this package
is pure 'C' it runs fairly quickly on a variety of platforms.  The keen 
developer could rewrite the root functions for a gain in speed.

How to use LNUM
----------------

    The simplest way to get LNUM into your program is to just '#include' it.
So at the top of your source you should have something like:

            #include "lnum.c"
            /* other includes here */

            main() {
                ...
                ...
                ...
            }
    
    To use the large num functions you have to define some large numbers.  
Which at first may seem a bit confusing but is not difficult once you get the
hang of it.  The skeleton looks like:

            sum() {
                word one[LSIZE], two[LSIZE];
            
                ...
                ...
                ...
            }

    Which defines two large nums called 'one' and 'two'.  If you noticed
they are simply arrays of 'word' (which is defined in the top of LNUM.C).  Each
array has LSIZE elements, this size cannot be changed at runtime.

    All of the functions are organized in a fashion like so:

        l_x(word *a, word *b, word *c)          [1]
        l_x_s(word *a, word *b)                 [2]
        l_x_d(word *a, word b)                  [3]

    Where in [1] 'a' is operated with 'b' ('a' is always on the left side of
the operator 'x') and the result stored in 'c'.

    In [2] 'a' is operated with 'b' ('a' is on the left side of the operator 
'x') and the result is stored back into 'a'.

    In [3] 'a' is operated on the word 'b' (not the large num) and stored 
back into 'a'.  This case is useful when you have to perform operations
with constants or other small words.

    For example:

        l_sub(word *a, word *b, word *c)

    Performs 'c' = 'a' - 'b'.

Simple Demo
------------

    Simply compile the demo just type

        CC LNUM.C -pof DEMO=

    to build LNUM.COM a demo program which functions as a simple command
    line calculator: LNUM <number#1> [+-*/%^] <number2>

Function List
--------------

) void l_copy(word *a, word *b)

    Set 'b' equal to 'a'.

) void l_clear(word *a)

    Set 'a' equal to zero.

) void l_set(word *a, word n)

    Set 'a' to the short number 'n'.  Useful for storing constants in a large
number.

) int l_iszero(word *a)

    Return true if 'a' is equal to zero.

) int l_cmp(word *a, word *b)

    Compare 'a' against 'b' and return L_LT, L_GT, L_EQ for <, > or ==.

) int l_cmp_d(word *a, word b)

    Compare 'a' against the short number 'b'.

) int l_shr(word *a, word *b)

    Perform 'b = a>>1' and return the carry bit out.

) int l_shr_s(word *a)

    Perform 'a >>= 1' and return the carry bit out.

) int l_shl(word *a, word *b)

    Perform 'b = a << 1' and return the carry bit out.

) int l_shl_s(word *a)

    Perform 'a <<= 1' and return the carry bit out.

) void l_add(word *a, word *b, word *c)

    Perform 'c = a + b'.

) void l_add_s(word *a, word *b)

    Perform 'a += b'.

) void l_add_d(word *a, word b)

    Perform 'a += b'.  Where 'b' is a short number.

) void l_sub(word *a, word *b, word *c)             [ c = a - b ]
) void l_sub_s(word *a, word *b)                    [ a -= b ]
) void l_sub_d(word *a, word b)                     [ a -= 'b']
) void l_mul(word *a, word *b, word *c)             [ c = ab ]
) void l_mul_s(word *a, word *b)                    [ a *= b ]
) void l_mul_d(word *a, word b)                     [ a *= 'b']
) void l_div(word *a, word *b, word *q, word *r)    [ q = a/b, r = a%b ]
) void l_div_s(word *a, word *b)                    [ a /= b ]
) void l_div_d(word *a, word b)                     [ a /= 'b']
) void l_mod(word *a, word *b, word *c)             [ c = a%b ]
) void l_mod_s(word *a, word *b)                    [ a %= b ]
) word l_mod_d(word *a, word b)                     [ returns a mod b ]

    Same model as above (see 'l_add' etc...).

) void l_addmod(word *a, word *b, word *m, word *c)

    Perform 'c = (a + b) mod m'.

) void l_submod(word *a, word *b, word *m, word *c)

    Perform 'c = (a - b) mod m'.

) void l_mulmod(word *a, word *b, word *m, word *c)

    Perform 'c = (ab) mod m'.

) void l_sqr(word *a)

    Perform 'a *= a'.

) void l_sqrmod(word *a, word *m, word *c)

    Perform 'c = (aa) mod m'.

) void l_expt(word *a, word *b, word *c)

    Raise 'a' to the power of 'b' and store in 'c'.

) void l_exptmod(word *a, word *b, word *m, word *c)

    Raise 'a' to the power of 'b', reduce modulo 'm' and store in 'c'.

) void l_gcd(word *a, word *b, word *c)

    Store the greatest common divisor of 'a' and 'b' into 'c'.

) void l_lcm(word *a, word *b, word *c)

    Store the least common multiple of 'a' and 'b' into 'c'.

) void l_invmod(word *a, word *n, word *b)

    Calculate the multiplicative inverse 'mod n' of 'a' and store in 'b'.

) void l_sqrt(word *n, word *N)

    Caclulate the square-root of 'n' into 'N'.

) void l_print(word *a, word radix, FILE *out)

    Write 'a' in base 'radix' to the stream 'out'.

) void l_println(word *a, word radix, FILE *out)

    Same as above but appends a new line char.

) void l_toradix(word *a, word radix, char *out)

    Convert 'a' into 'out' in base 'radix'.  Bases from 2 to 64 are allowed.

) void l_fromradix(char *a, word radix, word *b)

    Read from 'a' into 'b' using base 'radix'.

) void l_readraw(word *a, unsigned char *in, int len)

    Read 'a' from 'in' in binary.  The length of the word is specified in
'len'.

) int l_toraw(word *a, unsigned char *out)

    Convert 'a' to binary in 'out' and return the required number of bytes.

Tips and Suggestions
--------------------

    1.  Avoid l_x_d functions (such as l_add_d) if possible.  If you 
know for example you want to add all multiples of four up to 100, try
something like this: 

        sum() {
            word one[LSIZE], two[LSIZE];
            
            l_clear(one);
            l_clear(two);

            for (two[0] = 4; two[0] < 100; two[0] += 4)
                l_add_s(one, two);
        }

        This avoids the constant clearing required if you used 'l_set'.

    2.  Avoid l_x_s functions (such as l_add_s) if possible.  One method is
to use alternating buffers (see the source for l_toradix()).  Generally the
two classes of functions l_x_s and l_x_d are provided for ease of use.  For
maximum speed you have to minimize the manipulation being performed.

    3.  If the large nums are a power of 2 bigger then what you actually 
need (say 135 bits instead of 128) don't use the l_mod() function.  Instead
you can simply AND the bits at the end of the word.  For example:

        ...
        ... some functions ...

        a[8] &= 255;

        ...

        This would exclude the top seven bits effectively making it only keep
the 128 lower bits.  [This assumes BITS=16 and there are nine words].
