**************************************************************************

				   MAPM 

			       Version  3.56

			       July 19, 2000

			      Michael C. Ring

			    ringx004@tc.umn.edu

		    Latest release will be available at
		        http://tc.umn.edu/~ringx004

**************************************************************************
*                                                                        *
* Copyright (C) 1999, 2000   Michael C. Ring                             *
*                                                                        *
* This software is Freeware.                                             *
*                                                                        *
* Permission to use, copy, and distribute this software and its          * 
* documentation for any purpose with or without fee is hereby granted,   *
* provided that the above copyright notice appear in all copies and      *
* that both that copyright notice and this permission notice appear      *
* in supporting documentation.                                           *
*                                                                        *
* Permission to modify the software is granted, but not the right to     *
* distribute the modified code.  Modifications are to be distributed     *
* as patches to released version.                                        *
*                                                                        *
* This software is provided "as is" without express or implied warranty. *
*									 *
**************************************************************************

--------------------
MAPM Library History
--------------------

V 1.00  -  June 1, 1999    Initial Release

V 1.10  -  June 20, 1999   Use a stack implementation for local M_APM
			   variables instead of static variables.

			   Use a new faster algorithm for SIN & COS.

V 1.20  -  July 10, 1999   Improve the algorithm for ARCSIN and ARCCOS
			   when the input argument is near 1.0.

			   Added the 'DUP' operator to the 'calc' demo
			   program.

V 1.30  -  July 31, 1999   Added a function to output M_APM values as 
			   integers.

			   Supply another demo program which generates 
			   prime numbers (and uses the integer output
			   format).

			   Improved the 4 iterative routines, dynamically
			   adjusting the local precision each time through
			   the loop. Also changed the tolerance test to 
			   use integers (vs a MAPM number).

V 2.00  -  Aug 15, 1999    Added a 'fast' multiplication algorithm.

V 2.10  -  Sep 24, 1999    Added integer POW function.  Compute X^Y when
			   'Y' is an integer.

			   Added a random number generator (with a period
			   of 1.0E+15).

			   Added function to compute both sin and cos with 
			   one call.

V 2.15  -  Feb 10, 2000    Allow caller to easily use their own memory 
                           management functions.

			   Implement the real exponential algorithm as 
			   originally intended by David Bailey.

			   Delete the extra recursive function from the
			   fast multiply routine. 

			   Calculate a few extra digits in the intermediate
			   results of 'calc' so the final answers are 
			   always consistent.

V 2.20  -  Mar 30, 2000    Let log, arc-sin, and arc-cos determine the 
			   max number of iterations that should be required
			   to calculate a given precision level.

			   Optimize the raw series expansion for exp, sin,
			   and cos to use integers instead of MAPM numbers
			   in the tolerance test to determine loop termination.

V 2.25  -  Apr 2, 2000     Added a CBRT function (cube root)
			   
			   Added the hyperbolic SIN, COS, and TAN functions
			   plus their inverses.

			   Alias m_apm_asin to m_apm_arcsin. Also for acos,
			   atan, and atan2.

			   Updated CALC and VALIDATE to use the new functions.

V 3.00  -  Apr 7, 2000     Added the MAPM C++ wrapper class. Supplied by
			   Orion Sky Lawlor  (olawlor@acm.org)
			   This C++ class allows 'normal' syntax when using
			   the library. See below. 

V 3.05  -  Apr 14, 2000    Optimized the basic divide algorithm. It is now 
			   approx 10 - 15 % faster.

                           Optimized the fast multiply algorithm. It is now 
			   approx 2X faster. (depends on input numbers, 
			   sometimes I got 50%, other times 3X)

V 3.06  -  May 6, 2000     Optimized a few more functions.

 			   In 'CALC', recompute PI on the fly if more digits
			   are asked for than the default precision.

			   Changed default compile optimizations to use
			   '-O2' instead of '-O'. Just making a note 
			   in case some compilers don't handle this well.

V 3.10  -  May 21, 2000    Eliminated all warnings due to internal constants
			   lacking enough precision for a given calculation.
			   Any internal constant (like PI, log(2)) lacking the
			   precison needed for a given calculation will be 
			   re-computed on the fly as necessary.  The only 
			   warnings from the library now are legitimate domain 
			   errors, sqrt of a negative number, etc.

V 3.15  -  May 26, 2000    Optimize the factorial function. It is now approx
			   10X faster when N is large (i.e., N > 5000).
			   
			   Return 1 from pow function when computing 0^0.

V 3.16  -  Jun 24, 2000    Added makefile for Borland 5.2 / 5.5 C++ 
			   command line compilers for Win NT/9x.
 
                           Fixed link problems due to some C libraries not 
			   having native cube root or inverse hyperbolic
			   functions.

V 3.50  -  Jul 4, 2000     Added an FFT (Fast Fourier Transform) based 
			   fast multiplication. The FFT fast multiplication
			   is O(N * Log2(N)). The FFT used is from the 
			   Numerical Recipes book.

			   Fixed extern int declare in M_APM.H due to 
			   variable name mangling in MSVC C++ compiler.

V 3.51  -  Jul 7, 2000     Changed the FFT. The new FFT is from Takuya OOURA.
                           email: ooura@mmm.t.u-tokyo.ac.jp
 
                           Added build batch file for MSVC C++ compiler.
			   (Note: I can't verify this works since I don't 
			   have MSVC C++)

V 3.55  -  Jul 12, 2000    Optimized the FFT set-up wrapper function. Convert 
			   MAPM base 100 numbers into base 10000 before 
			   invoking the FFT. (2X speed improvement and 1/2
			   the RAM usage)

			   Use the AGM (Arithmetic-Geometric Mean) to 
			   calculate PI when a more precise value is needed.

			   Added a real Makefile for Unix builds (finally!)

V 3.56  -  Jul 19, 2000    Decrease the max number of bytes the FFT can
			   handle. *Worst* case inputs (all 9's) could have 
			   caused the FFT math to overflow.

			   Added a build batch file for older Borland 
			   compilers. (Works with Turbo C++ 3.00)

**************************************************************************

	        ---------------------------------------
       	        Mike's Arbitrary Precision Math Library
	        ---------------------------------------

Mike's Arbitrary Precision Math Library is a set of functions that 
allow the user to perform math to any level of accuracy that is
desired. The inspiration for this library was Lloyd Zusman's similar
APM package that was released in ~1988. I borrowed some of his ideas
in my implementation, creating a new data type (MAPM) and how the data
type was used by the user. However, there were a few things I wanted 
my library to do that the original library did not :

1) Round a value to any desired precision. This is very handy when 
   multiplying for many iterations. Since multiplication guarantees an
   exact result, the number of digits will grow without bound. I wanted
   a way to trim the number of significant digits that were retained.

2) A natural support for floating point values. From most of the other
   libraries I looked at, they seem to have a preference for integer
   only type math manipulations. This library will also do integer only
   math if you desire.

   And if a library can only do integers, it can't do ...

3) Trig functions and other common C math library functions. This library
   will perform the following functions to any desired precision level :
   SQRT, CBRT, SIN, COS, TAN, ARC-SIN, ARC-COS, ARC-TAN, ARC-TAN2, LOG, 
   LOG10, EXP, POW, SINH, COSH, TANH, ARC-SINH, ARC-COSH, ARC-TANH, and 
   also FACTORIAL.  The full 'math.h' is not duplicated, though I think 
   these are most of the important ones. My definition of what's important 
   is what I've actually used in a real application.


(I really wasn't sure what to call this library. 'Arbitrary Precision Math'
is a defacto standard for what this does, but that name was already taken, 
so I just put an 'M' in front of it ...)

**************************************************************************

KNOWN BUGS : None

**************************************************************************

IF YOU ARE IN A HURRY ...

UNIX:  (assumes gcc compiler)

run    make          (build library + 3 executables)

--- OR ---

run:   mklib         (this will create the library, lib_mapm.a)

run:   mkdemo        (this will create 3 executables, 'calc', 'validate',
                      and 'primenum')


DOS / Win NT/9x  (in a DOS window for NT/9x):

       Depends on your compiler. 

       GCC for DOS:    
           run : mkallgcc.bat             (builds library + 3 executables)


       Borland C++ 5.2 / 5.5
           run : make -f makefile.b32              (builds library)
	   run : mkdemb32.bat                      (builds 4 demo programs)


       Borland C++ 3.00
	   run : mkalltcc.bat             (builds library + 3 executables)


       Microsoft Visual C++
           run : mk_msvc.bat              (builds library + 4 executables)


       Microsoft C 8.00c   run  mklibmsc.bat       (builds library)
       Microsoft C 5.1     run  mklibm51.bat       (builds library)
       Both (5.1 & 8.00c)  run  mkdemo.bat         (builds 3 executables)


**************************************************************************

calc:  This is a command line version of an RPN calculator. If you are 
       familiar with RPN calculators, the use of this program will be 
       quite obvious. The default is 30 decimal places but this can be
       changed with the '-d' command line option. This is not an 
       interactive program, it just computes an expression from the command
       line. Run 'calc' with no arguments to get a list of the operators.

       compute : (345.2 * 87.33) - (11.88 / 3.21E-2) 

       calc 345.2 87.33 x 11.88 3.21E-2 / - 
       result: [2.977622254205607476635514018692E+4]

       compute PI to 70 decimal places :  (6 * arcsin(0.5))

       calc -d70 6 .5 as x
       result :
3.1415926535897932384626433832795028841971693993751058209749445923078164E+0

validate : This program will compare the MAPM math functions to the C
           standard library functions, like sqrt, sin, exp, etc.  This 
	   should give the user a good idea that the library is operating 
	   correctly. The program will also compute some known quantities 
	   to 70 digits of precision, like PI, log(2), etc. There was nothing 
	   special about '70' other than that number of digits fit nicely 
	   on one line. 

primenum:  This program will generate the first 10 prime numbers starting
	   with the number entered as an argument.

	   Example:  primenum 150000 will output (actually 1 per line):

           150001, 150011, 150041, 150053, 150061, 
	   150067, 150077, 150083, 150089, 150091

**************************************************************************

To use the library, simply include 'm_apm.h' and link your program
with the library, lib_mapm.a (unix) or lib_mapm.lib (dos). 

For unix builds, you also may need to specify the math library (-lm) when 
linking. The reason is some of the MAPM functions use an iterative algorithm. 
When you use an iterative solution, you have to supply an initial guess. I 
use the standard math library to generate this initial guess. I debated 
whether this library should be stand-alone, i.e. generate it's own initial 
guesses with some algorithm. In the end, I decided using the standard math 
library would not be a big inconvienence and also it was just too tempting 
having an immediate 15 digits of precision. When you prime the iterative 
routines with 15 accurate digits, the MAPM functions converge considerably 
faster.

See the file 'algorithms.used' to see a description of the algorithms I 
used in the library. Some I derived on my own, others I borrowed from 
people smarter than me. Version 2 of the library now supports a 'fast'
multiplication algorithm. The algorithm used is described in the 
algorithms.used file. A considerable amount of time went into finding
fast algorithms for the library. However, some could possibly be even 
better. If anyone has a more efficient algorithm for any of these 
functions, I would like to here from you.

See the file 'function.ref' to see a description of all the functions in 
the library and the calling conventions, prototypes, etc.

See the file 'struct.ref' which documents how I store the numbers internally
in the MAPM data structure. This will not be needed for normal use, but it
will be very useful if you need to change/add to the existing library.

**************************************************************************

QUICK TEMPLATE FOR NORMAL USE :

The MAPM math is done on a new data type called "M_APM".  This is
actually a pointer to a structure, but the contents of the structure
should never be manipulated: all operations on MAPM entities are done
through a functional interface.

The MAPM routines will automatically allocate enough space in their 
results to hold the proper number of digits.

The caller must initialize all MAPM values before the routines can
operate on them (including the values intended to contain results of
calculations).  Once this initialization is done, the user never needs
to worry about resizing the MAPM values, as this is handled inside the
MAPM routines and is totally invisible to the user.

The result of a MAPM operation cannot be one of the other MAPM operands.
If you want this to be the case, you must put the result into a
temporary variable and then assign (m_apm_copy) it to the appropriate operand.

All of the MAPM math functions begin with m_apm_*.

There are some predefined constants for your use. In case it's not obvious, 
these should never appear as a 'result' parameter in a function call.

The following constants are available : (declared in m_apm.h)

MM_Zero             MM_One              MM_Two             MM_Three
MM_Four             MM_Five             MM_Ten
MM_PI               MM_HALF_PI          MM_2_PI            MM_E
MM_LOG_E_BASE_10    MM_LOG_10_BASE_E    MM_LOG_2_BASE_E    MM_LOG_3_BASE_E


The non-integer constants above (PI, log(2), etc) are accurate to 128 
decimal places. The file mapmcnst.c contains these constants. I've 
included 512 digit constants in this file also that are commented out. 
If you need more than 512 digits, you can simply use the 'calc' program 
to generate more precise constants (or create more precise constants at
run-time in your app).  The number of significant digits in the constants 
should be 6-8 more than the value specified in the #define. 


Basic plan of attack:

(1)  get your 'numbers' into M_APM format.
(2)  do your high precision math.
(3)  get the M_APM numbers back into a format you can use.


--------  (1)  --------

#include "m_apm.h"        /* must be included before any M_APM 'declares' */

M_APM    area_mapm;                /* declare your variables */
M_APM    tmp_mapm;
M_APM    array_mapm[10];           /* can use normal array notation */
M_APM    array2d_mapm[10][10];

area_mapm = m_apm_init()           /* init your variables */
tmp_mapm  = m_apm_init();

for (i=0; i < M; i++)              /* must init every element of the array */
  array_mapm[i] = m_apm_init();
  
for (i=0; i < M; i++)    
   for (j=0; j < N; j++)  
     array2d_mapm[i][j] = m_apm_init();
  
/*
 *   there are 3 ways to convert your number into an M_APM
 *   (see the file function.ref)
 *
 *   a) literal string   (exponential notation OK)
 *   b) long variable
 *   c) double variable
 */

m_apm_set_string(tmp_mapm, "5.3286E-7");
m_apm_set_long(array_mapm[6], -872253L);
m_apm_set_double(array2d_mapm[3][7], -529.4486711);


--------  (2)  --------

do your math ...

m_apm_add(cc_mapm, aa_mapm, MM_PI);
m_apm_divide(bb_mapm, DECIMAL_PLACES, aa_mapm, MM_LOG_2_BASE_E);
m_apm_sin(bb_mapm, DECIMAL_PLACES, aa_mapm);
whatever ...

  
/*
 *   There are 2 functions for converting an M_APM number into 
 *   something useful.  (SEE THE FILE 'function.ref')
 *
 *   For both functions, M_APM number -> string is the conversion
 *
 *   ===================
 *   ====  METHOD 1 ==== : Meant for use with floating point values
 *   ===================
 *
 *   the format will be in scientific (exponential) notation 
 *
 *   output string = [-]n.nnnnnE+x   or ...E-x
 *
 *   where 'n' are digits and the exponent will be always be present, 
 *   even E+0
 *
 *   it's easy to convert this to a double:
 *
 *   double dtmp = atof(out_buffer);
 *
 *
 *   ===================
 *   ====  METHOD 2 ==== : Meant for use with integer values
 *   ===================
 *
 *   the format will simply be digits with a possible leading '-' sign.
 *
 *   output string = [-]nnnnnn
 *
 *   where 'n' are digits.
 *
 *   it's easy to convert this to a long :
 *   long mtmp = atol(out_buffer);
 *
 *   ... or an int :
 *   int itmp = atoi(out_buffer);
 *
 *   Note that if the M_APM number has a fractional portion, the fraction
 *   will be truncated and only the integer portion will be output.
 */

--------  (3)  --------

char  out_buffer[256];

m_apm_to_string(out_buffer, DECIMAL_PLACES, mapm_number);

m_apm_to_integer_string(out_buffer, mapm_number);

**************************************************************************

MAPM C++ WRAPPER CLASS:

Orion Sky Lawlor (olawlor@acm.org) has added a very nice C++ wrapper
class to m_apm.h. This C++ class will have no effect if you just use
a normal C compiler. The library will operate as before with no user
impacts. 

For now, I recommend compiling the library as 'C'. In order to compile
the library as C++, all the function declarations will need to be updated.
This may or may not happen in the near future. Since the C++ wrapper 
class works very nicely as is, there is no pressing need to update the
entire library yet. 

See the file 'cpp_function.ref' to see a description of how to use
the MAPM class.

To compile and link the C++ demo program: (assuming the library is 
already built)

UNIX: 

g++ cpp_demo.cpp lib_mapm.a -s -o cpp_demo -lm

GCC for DOS: (gxx is the C++ compiler)

gxx cpp_demo.cpp lib_mapm.a -s -o cpp_demo.exe -lm


Using the C++ wrapper allows you to do things like:

// Compute the factorial of the integer n

MAPM factorial(MAPM n)
{
	MAPM i;
	MAPM product=1;
	for (i=2;i<=n;i++)
		product*=i;
	return product;
}


The syntax is the same as if you were just writing normal code, but all
the computations will be performed with the high precision math library,
using the new 'datatype' MAPM.

The default precision of the computations is as follows:

Addition, subtraction, and multiplication will maintain ALL significant
digits. 

All other operations (divide, sin, etc) will use the following rules:

1) if the operation uses only one input value [y = sin(x)], the result 'y'
   will be the same precision as 'x', with a minimum of 30 digits if 'x' is
   less than 30 digits.

2) if the operation uses two input values [z = atan2(y,x)], the result 'z'
   will be the max digits of 'x' or 'y' with a minimum of 30.

The default precision is 30 digits. You can change the precision at
any time with the function 'm_apm_cpp_precision'. (See function.ref)

---->        m_apm_cpp_precision(80);

will result in all operations being accurate to a minimum of 80 significant 
digits. If any operand contains more than the minimum number of digits, then
the result will contain the max number of digits of the operands.


NOTE!: Some real life use with the C++ wrapper has revealed a certain
       tendency for a program to become quite slow after many iterations
       (like in a for/while loop).  After a little debug, the reason
       became clear. Remember that multiplication will maintain ALL
       significant digits :

       20 digit number x 20 digit number =  40 digits
       40 digit number x 40 digit number =  80 digits
       80 digit number x 80 digit number = 160 digits
       etc.

       So after numerous iterations, the number of significant digits
       was growing without bound. The easy way to fix the problem is
       to simply *round* your result after a multiply or some other
       complex operation. For example:

       #define MAX_DIGITS 256
      
       p1 = (p0 * sin(b1) * exp(1 + u1)) / sqrt(1 + b1);
       p1 = p1.round(MAX_DIGITS);

       If you 'round' as shown here, ypur program will likely be
       nearly as fast as a straight 'C' version.


If you have any questions or problems with the C++ wrapper, please let
me know. I am not very C++ proficient, but I'd still like to know about any
problems.  Orion Sky Lawlor (olawlor@acm.org) is the one who implemented 
the MAPM class, so he'll have to resolve any real hardcore problems, if you
have any.


**************************************************************************

TESTING : 

Testing the library was interesting.  How do I know it's right?  Since I 
test the library against the standard C runtime math library (see below)
I have high confidence that the MAPM library is giving correct results.
The logic here is the basic algorithms are independent of the number of 
digits calculated, more digits just takes longer.

The MAPM library has been tested in the following environments :

Linux i486 gcc 2.7.2.3
Linux i686 gcc 2.91.66
HP-UX Ver 9.x and 10.x
Sun 5.5.1  (output from uname)
Sun Solaris 2.6 / gcc 2.95.1
DOS 5.0 using Microsoft C 5.1 and 8.00c  (16 bit EXEs)
DOS 5.0 using GCC 2.8.1 for DOS
DOS 5.0 using GCC 2.95.2 for DOS
WIN NT+SP5 using Borland C++ 5.02 IDE, 5.2 & 5.5 command line.


As a general rule, when calculating a quantity to a given number of decimal 
places, I calculated 4-6 extra digits and then rounded the result to what was 
asked for. I decided to be conservative and give a correct answer rather than 
to be faster and possibly have the last 2-3 digits in error. Also, some of 
the functions call other functions (calculating arc-cos will call cos, log 
will call exp, etc.) so I had to calculate a few extra digits in each iteration
to guarantee the loops terminated correctly.

1)  I debugged the 4 basic math operations. I threw numerous test cases at
    each of the operations until I knew they were correct.  

    Also note that the math.h type functions all call the 4 basic operations 
    numerous times. So if all the math.h functions work, it is highly 
    probable the 4 basic math operations work also.
    
2)  'math.h' type functions.   

     SQRT:     Not real hard to check. Single stepping through the iterative
               loop showed it was always converging to the sqrt.

     CBRT:     Similar to sqrt, single stepping through the iterative loop 
     	       showed it was always converging to the cube root.

     EXP:      I wrote a separate algorithm which expanded the Taylor series
               manually and compared the results against the library.

     POW:      Straightforward since this just calls 'EXP'.

     LOG:      I wrote a separate algorithm which expanded the Taylor series
               manually and compared the results against the library. This
	       took a long time to execute since the normal series converges
	       VERY slowly for the log function. This is why the LOG function
	       uses an iterative algorithm.

     LOG10:    Straightforward since this just calls 'LOG'.

     SIN/COS:  I wrote a separate algorithm which expanded the Taylor series
               manually and compared the results against the library.

     TAN:      Straightforward since this just calls 'SIN' and 'COS'.

     ARC-x:    Single stepping through the iterative loop showed the arc 
               family of functions were always converging. Also used these 
	       to compute PI. The value of PI is now known to many, many 
	       digits. I computed PI to 1000+ digits by computing:

	       6 * arcsin(0.5)  and  4 * arctan(1)  and  3 * arccos(0.5)

	       and compared the output to the published 'real' values of PI.

	       The arc family of functions exercise considerable portions 
	       of the library.

  HYPERBOLIC:  The hyperbolic functions just use exp, log, and the 4 basic
  	       math operations. All of these functions simply use other 
	       existing functions in the library.
  
     FINALLY:  Run the program 'validate'. This program compares the first 
               13-14 significant digits of the standard C library against
	       the MAPM library. If this program passes, you can feel 
	       confident that the MAPM library is giving correct results.
	       This is because the basic algorithms do not change when
	       calculating more digits, it just takes longer.

**************************************************************************
