Dec 102017
 
C precision math library.
File APM.ZIP from The Programmer’s Corner in
Category C Source Code
C precision math library.
File Name File Size Zip Size Zip Type
ADDSUB.C 13292 4318 deflated
APM.ARF 95 65 deflated
APM.H 14634 4956 deflated
APMLOCAL.H 10616 4052 deflated
AUTHOR.NOT 828 497 deflated
CALC.C 18723 5475 deflated
FUNCTION 16743 4692 deflated
LICENSE 8342 3315 deflated
MAKEFILE 1507 600 deflated
MAKEFILE.MSC 977 318 deflated
MEMORY.C 13116 4688 deflated
MISC.C 18872 5475 deflated
MULDIV.C 16553 5402 deflated
README 7206 3069 deflated
README.1ST 116 96 deflated
TEST.ZIP 3451 3228 deflated
UTILS.C 28270 7514 deflated

Download File APM.ZIP Here

Contents of the README file



Arbitrary Precision Math Library

The Arbitrary Precision Math Library is a series of routines that
allows the user to perform math to any level of accuracy that is
desired. These APM entities ("APM" == "Arbitrary Precision Math") can
be initialized from character strings or from long integers, and they
can be converted back into character strings by a routine that allows
simple formatting. With the exception of the routines that do
division, the results of APM operations are guaranteed to contain
enough precision to hold exact values. The APM routines will
automatically allocate enough space in their results to hold the
proper number of digits.

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

APM items can be represented in any of 36 bases: 2 through 36 and
10000. The latter is quite useful: numbers that are represented in
bases that are powers of 10 are quite easy to accurately convert to
and from character strings containing their decimal representation,
and 10000 is the largest power of 10 that fits into a short integer
(16 bits). The base must fit into a short integer since calculations
internal to the APM routines need up to twice as much storage as is
needed to hold the base, and the largest unit we can deal with easily
is a long integer (2 shorts). It turns out that speed improves and
memory usage decreases as the magnitude of the base increases, so base
10000 is a win in both counts. I have done some informal benchmarks
in which base 10000 is 6 to 10 times faster than base 10 for numbers
with 15 - 20 decimal digits of precision.

Although there is a multitude of bases, there is as yet no provision
for conversion from one base to another, except for the special case
of converting between base-10 character strings and base-10000 APM
values. All the input APM parameters to any given APM routine must be
of the same base.

The caller must initialize all APM 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 APM values, as this is handled inside the
APM routines and is totally invisible to the user.

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

All of the routines set the value of a global integer called
"apm_errno" to an error status: 0 means the operation succeeded, > 0
means there was a warning but that there still is a result, and < 0
means there was an error which prohibited the operation from
completing. Except where otherwise noted, the routines return this
same status value.

The caller has the option of registering a handler for errors and
warnings. If this has been done, the handler will be invoked as each
APM routine returns, and it will be passed appropriate information as
to the status of the call to this APM routine. With a registered
error handler it is not necessary for the caller to check the error
code after each call to a APM routine.

For ease of debugging, each APM routine is actually a macro that saves
the file name and line number and then calls a function of a slightly
different name. This allows the error handler to report the exact
location of the APM operation which caused the error. The macros you
will use have names of the form "apmRoutineName". To get the
corresponding actual function name (say, when using a debugger),
replace all capital letters with an underbar ("_") followed by its
lower-case counterpart. For example, for a hypothetical routine
called "apmRoutineName", the actual function will be named
"apm_routine_name". You should never explicitly call the actual
function.

You should avoid using symbols that start with the characters "APM_"
and "apm_", as they may clash with symbols that already exist in the
APM Library.

There is one routine for each basic arithmetic operation such as
adding, subtracting, etc. This can become cumbersome when the result
of a complicated expression is desired. Therefore, I have added a
routine that will perform a series of operations in the manner of an
RPN ("Reverse Polish Notation") calculator. See the routine 'apmCalc'
(below) for more details.

In my original version of this library, I discovered that a great deal
of system overhead was wasted allocating and deallocating APM values.
So, I adopted what has turned out to be a noticibly faster allocation
scheme: newly allocated APM values are stored in a list. When the
user disposes of one of these, it isn't really freed: its entry in the
list is marked as unused. Subsequent attempts to allocate a new APM
value will make use of any existing entries in this list that are
marked as unused instead of allocating a new entry. Only when there
are no unused entries in the list will a new entry be allocated.
There is a routine that can be called which will perform a garbage
collection: i.e., it actually frees all unused APM entries (see
'apmGarbageCollect', below).

A file called apm.h must be included in all programs that use the APM
routines. It defines the "APM" data type, the error codes, the
apm_errno variable, and several other things.

This software was written in as portable a manner as possible. I have
gotten it running successfully under several environments: on a Sun
3/xxx using SunOS 3.5 and 4.0, on an IBM RT running under AIX, under
MSDOS on an IBM PC using Microsoft C version 5.1 and Turbo C version
1.5 (or was it version 2.0?). There are two makefiles: the one called
"Makefile" is the unix version ... it works under SunOS 3.5 and I
presume it would be easy to alter it to work under other unix
environments; the one called "makefile.msc" will build the library
under MSDOS using Microsoft C version 5.1 ... it is meant to run with
the make program "PC/MAKE".

I'm sure that some of you will find ways of enhancing and speeding up
the routines in this library. Time permitting, I will be doing that
as well. I urge you to post your bug fixes and changes to the net and
mail them to me at my address below, so they might be incorporated
into a later version of this library. Some suggested areas of
enhancement and optimization are:

1)Somehow speeding up the memory allocation scheme.

2)Some sort of floating-point/APM conversion. I left this out
because of the widely varying floating-point formats that
exist on the various machines these routines can and might run
on, and because I intended APM to *replace* floating-point,
not to work in conjunction with it.

3)Base conversion.

4)Roots, powers, logarithms, trig functions, exponential functions,
etc.

5) More productions in the makefiles ("install", "rdist", etc.).

6) A fancy installation script.


7)Writing a man page for all this.


Contents of the README.1ST file



Arbitrary Precision Math Library

The Arbitrary Precision Math Library is a series of routines that
allows the user to perform math to any level of accuracy that is
desired. These APM entities ("APM" == "Arbitrary Precision Math") can
be initialized from character strings or from long integers, and they
can be converted back into character strings by a routine that allows
simple formatting. With the exception of the routines that do
division, the results of APM operations are guaranteed to contain
enough precision to hold exact values. The APM routines will
automatically allocate enough space in their results to hold the
proper number of digits.

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

APM items can be represented in any of 36 bases: 2 through 36 and
10000. The latter is quite useful: numbers that are represented in
bases that are powers of 10 are quite easy to accurately convert to
and from character strings containing their decimal representation,
and 10000 is the largest power of 10 that fits into a short integer
(16 bits). The base must fit into a short integer since calculations
internal to the APM routines need up to twice as much storage as is
needed to hold the base, and the largest unit we can deal with easily
is a long integer (2 shorts). It turns out that speed improves and
memory usage decreases as the magnitude of the base increases, so base
10000 is a win in both counts. I have done some informal benchmarks
in which base 10000 is 6 to 10 times faster than base 10 for numbers
with 15 - 20 decimal digits of precision.

Although there is a multitude of bases, there is as yet no provision
for conversion from one base to another, except for the special case
of converting between base-10 character strings and base-10000 APM
values. All the input APM parameters to any given APM routine must be
of the same base.

The caller must initialize all APM 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 APM values, as this is handled inside the
APM routines and is totally invisible to the user.

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

All of the routines set the value of a global integer called
"apm_errno" to an error status: 0 means the operation succeeded, > 0
means there was a warning but that there still is a result, and < 0
means there was an error which prohibited the operation from
completing. Except where otherwise noted, the routines return this
same status value.

The caller has the option of registering a handler for errors and
warnings. If this has been done, the handler will be invoked as each
APM routine returns, and it will be passed appropriate information as
to the status of the call to this APM routine. With a registered
error handler it is not necessary for the caller to check the error
code after each call to a APM routine.

For ease of debugging, each APM routine is actually a macro that saves
the file name and line number and then calls a function of a slightly
different name. This allows the error handler to report the exact
location of the APM operation which caused the error. The macros you
will use have names of the form "apmRoutineName". To get the
corresponding actual function name (say, when using a debugger),
replace all capital letters with an underbar ("_") followed by its
lower-case counterpart. For example, for a hypothetical routine
called "apmRoutineName", the actual function will be named
"apm_routine_name". You should never explicitly call the actual
function.

You should avoid using symbols that start with the characters "APM_"
and "apm_", as they may clash with symbols that already exist in the
APM Library.

There is one routine for each basic arithmetic operation such as
adding, subtracting, etc. This can become cumbersome when the result
of a complicated expression is desired. Therefore, I have added a
routine that will perform a series of operations in the manner of an
RPN ("Reverse Polish Notation") calculator. See the routine 'apmCalc'
(below) for more details.

In my original version of this library, I discovered that a great deal
of system overhead was wasted allocating and deallocating APM values.
So, I adopted what has turned out to be a noticibly faster allocation
scheme: newly allocated APM values are stored in a list. When the
user disposes of one of these, it isn't really freed: its entry in the
list is marked as unused. Subsequent attempts to allocate a new APM
value will make use of any existing entries in this list that are
marked as unused instead of allocating a new entry. Only when there
are no unused entries in the list will a new entry be allocated.
There is a routine that can be called which will perform a garbage
collection: i.e., it actually frees all unused APM entries (see
'apmGarbageCollect', below).

A file called apm.h must be included in all programs that use the APM
routines. It defines the "APM" data type, the error codes, the
apm_errno variable, and several other things.

This software was written in as portable a manner as possible. I have
gotten it running successfully under several environments: on a Sun
3/xxx using SunOS 3.5 and 4.0, on an IBM RT running under AIX, under
MSDOS on an IBM PC using Microsoft C version 5.1 and Turbo C version
1.5 (or was it version 2.0?). There are two makefiles: the one called
"Makefile" is the unix version ... it works under SunOS 3.5 and I
presume it would be easy to alter it to work under other unix
environments; the one called "makefile.msc" will build the library
under MSDOS using Microsoft C version 5.1 ... it is meant to run with
the make program "PC/MAKE".

I'm sure that some of you will find ways of enhancing and speeding up
the routines in this library. Time permitting, I will be doing that
as well. I urge you to post your bug fixes and changes to the net and
mail them to me at my address below, so they might be incorporated
into a later version of this library. Some suggested areas of
enhancement and optimization are:

1)Somehow speeding up the memory allocation scheme.

2)Some sort of floating-point/APM conversion. I left this out
because of the widely varying floating-point formats that
exist on the various machines these routines can and might run
on, and because I intended APM to *replace* floating-point,
not to work in conjunction with it.

3)Base conversion.

4)Roots, powers, logarithms, trig functions, exponential functions,
etc.

5) More productions in the makefiles ("install", "rdist", etc.).

6) A fancy installation script.


7)Writing a man page for all this.
The files in TEST.ARC are to be installed in a separate directory
(they duplicate names of files in APM.ARC).




 December 10, 2017  Add comments

Leave a Reply