mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
483 lines
19 KiB
Plaintext
483 lines
19 KiB
Plaintext
USING THE ARBITRARY PRECISION ROUTINES IN A C PROGRAM
|
|
|
|
Part of the calc release consists of an arbitrary precision math link library.
|
|
This link library is used by the calc program to perform its own calculations.
|
|
If you wish, you can ignore the calc program entirely and call the arbitrary
|
|
precision math routines from your own C programs.
|
|
|
|
The link library is called libcalc.a, and provides routines to handle arbitrary
|
|
precision arithmetic with integers, rational numbers, or complex numbers.
|
|
There are also many numeric functions such as factorial and gcd, along
|
|
with some transcendental functions such as sin and exp.
|
|
|
|
Take a look at the sample sub-directory. It contains a few simple
|
|
examples of how to use libcalc.a that might be helpful to look at
|
|
after you have read this file.
|
|
|
|
------------------
|
|
FIRST THINGS FIRST
|
|
------------------
|
|
|
|
...............................................................................
|
|
. .
|
|
. You MUST call libcalc_call_me_first() prior to using libcalc lib functions! .
|
|
. .
|
|
...............................................................................
|
|
|
|
The function libcalc_call_me_first() takes no args and returns void. You
|
|
need call libcalc_call_me_first() only once.
|
|
|
|
-------------
|
|
INCLUDE FILES
|
|
-------------
|
|
|
|
To use any of these routines in your own programs, you need to include the
|
|
appropriate include file. These include files are:
|
|
|
|
zmath.h (for integer arithmetic)
|
|
qmath.h (for rational arithmetic)
|
|
cmath.h (for complex number arithmetic)
|
|
|
|
You never need to include more than one of the above files, even if you wish
|
|
to use more than one type of arithmetic, since qmath.h automatically includes
|
|
zmath.h, and cmath.h automatically includes qmath.h.
|
|
|
|
The prototypes for the available routines are listed in the above include
|
|
files. Some of these routines are meant for internal use, and so aren't
|
|
convenient for outside use. So you should read the source for a routine
|
|
to see if it really does what you think it does. I won't guarantee that
|
|
obscure internal routines won't change or disappear in future releases!
|
|
|
|
When calc is installed, all of the include files needed to build
|
|
libcalc.a along with the link library itself are installed into ${LIBDIR}.
|
|
|
|
External programs may want to compile with:
|
|
|
|
-I${LIBDIR} -L${LIBDIR} -lcalc
|
|
|
|
--------------
|
|
ERROR HANDLING
|
|
--------------
|
|
|
|
Your program MUST provide a function called math_error. This is called by
|
|
the math routines on an error condition, such as malloc failures or a
|
|
division by zero. The routine is called in the manner of printf, with a
|
|
format string and optional arguments. (However, none of the low level math
|
|
routines currently uses formatting, so if you are lazy you can simply use
|
|
the first argument as a simple error string.) For example, one of the
|
|
error calls you might expect to receive is:
|
|
|
|
math_error("Division by zero");
|
|
|
|
Your program can handle errors in basically one of two ways. Firstly, it
|
|
can simply print the error message and then exit. Secondly, you can make
|
|
use of setjmp and longjmp in your program. Use setjmp at some appropriate
|
|
level in your program, and use longjmp in the math_error routine to return
|
|
to that level and so recover from the error. This is what the calc program
|
|
does.
|
|
|
|
For convenience, the link library libcalc.a contains a math_error routine.
|
|
By default, this routine simply prints a message to stderr and then exits.
|
|
By simply linking in this link library, any calc errors will result in a
|
|
error message on stderr followed by an exit.
|
|
|
|
External programs that wish to use this math_error may want to compile with:
|
|
|
|
-I${LIBDIR} -L${LIBDIR} -lcalc
|
|
|
|
If one sets up calc_jmp_buf, and then sets calc_jmp to non-zero then
|
|
this routine will longjmp back (with the value of calc_jmp) instead.
|
|
In addition, the last calc error message will be found in calc_error;
|
|
this error is not printed to stderr. The calc error message will
|
|
not have a trailing newline.
|
|
|
|
For example:
|
|
|
|
#include <setjmp.h>
|
|
|
|
extern jmp_buf calc_jmp_buf;
|
|
extern int calc_jmp;
|
|
extern char *calc_error;
|
|
int error;
|
|
|
|
...
|
|
|
|
if ((error = setjmp(calc_jmp_buf)) != 0) {
|
|
|
|
/* reinitialize calc after a longjmp */
|
|
reinitialize();
|
|
|
|
/* report the error */
|
|
printf("Ouch: %s\n", calc_error);
|
|
}
|
|
calc_jmp = 1;
|
|
|
|
---------------
|
|
OUTPUT ROUTINES
|
|
---------------
|
|
|
|
The output from the routines in the link library normally goes to stdout. You
|
|
can divert that output to either another FILE handle, or else to a string.
|
|
Read the routines in zio.c to see what is available. Diversions can be
|
|
nested.
|
|
|
|
You use math_setfp to divert output to another FILE handle. Calling
|
|
math_setfp with stdout restores output to stdout.
|
|
|
|
Use math_divertio to begin diverting output into a string. Calling
|
|
math_getdivertedio will then return a string containing the output, and
|
|
clears the diversion. The string is reallocated as necessary, but since
|
|
it is in memory, there are obviously limits on the amount of data that can
|
|
be diverted into it. The string needs freeing when you are done with it.
|
|
|
|
Calling math_cleardiversions will clear all the diversions to strings, and
|
|
is useful on an error condition to restore output to a known state. You
|
|
should also call math_setfp on errors if you had changed that.
|
|
|
|
If you wish to mix your own output with numeric output from the math routines,
|
|
then you can call math_chr, math_str, math_fill, math_fmt, or math_flush.
|
|
These routines output single characters, output null-terminated strings,
|
|
output strings with space filling, output formatted strings like printf, and
|
|
flush the output. Output from these routines is diverted as described above.
|
|
|
|
You can change the default output mode by calling math_setmode, and you can
|
|
change the default number of digits printed by calling math_setdigits. These
|
|
routines return the previous values. The possible modes are described in
|
|
zmath.h.
|
|
|
|
--------------
|
|
USING INTEGERS
|
|
--------------
|
|
|
|
The arbitrary precision integer routines define a structure called a ZVALUE.
|
|
This is defined in zmath.h. A ZVALUE contains a pointer to an array of
|
|
integers, the length of the array, and a sign flag. The array is allocated
|
|
using malloc, so you need to free this array when you are done with a
|
|
ZVALUE. To do this, you should call zfree with the ZVALUE as an argument
|
|
(or call freeh with the pointer as an argument) and never try to free the
|
|
array yourself using free. The reason for this is that sometimes the pointer
|
|
points to one of two statically allocated arrays which should NOT be freed.
|
|
|
|
The ZVALUE structures are passed to routines by value, and are returned
|
|
through pointers. For example, to multiply two small integers together,
|
|
you could do the following:
|
|
|
|
ZVALUE z1, z2, z3;
|
|
|
|
itoz(3L, &z1);
|
|
itoz(4L, &z2);
|
|
zmul(z1, z2, &z3);
|
|
|
|
Use zcopy to copy one ZVALUE to another. There is no sharing of arrays
|
|
between different ZVALUEs even if they have the same value, so you MUST
|
|
use this routine. Simply assigning one value into another will cause
|
|
problems when one of the copies is freed. However, the special ZVALUE
|
|
values _zero_ and _one_ CAN be assigned to variables directly, since their
|
|
values of 0 and 1 are so common that special checks are made for them.
|
|
|
|
For initial values besides 0 or 1, you need to call itoz to convert a long
|
|
value into a ZVALUE, as shown in the above example. Or alternatively,
|
|
for larger numbers you can use the atoz routine to convert a string which
|
|
represents a number into a ZVALUE. The string can be in decimal, octal,
|
|
hex, or binary according to the leading digits.
|
|
|
|
Always make sure you free a ZVALUE when you are done with it or when you
|
|
are about to overwrite an old ZVALUE with another value by passing its
|
|
address to a routine as a destination value, otherwise memory will be
|
|
lost. The following shows an example of the correct way to free memory
|
|
over a long sequence of operations.
|
|
|
|
ZVALUE z1, z2, z3;
|
|
|
|
z1 = _one_;
|
|
atoz("12345678987654321", &z2);
|
|
zadd(z1, z2, &z3);
|
|
zfree(z1);
|
|
zfree(z2);
|
|
zsquare(z3, &z1);
|
|
zfree(z3);
|
|
itoz(17L, &z2);
|
|
zsub(z1, z2, &z3);
|
|
zfree(z1);
|
|
zfree(z2);
|
|
zfree(z3);
|
|
|
|
There are some quick checks you can make on integers. For example, whether
|
|
or not they are zero, negative, even, and so on. These are all macros
|
|
defined in zmath.h, and should be used instead of checking the parts of the
|
|
ZVALUE yourself. Examples of such checks are:
|
|
|
|
ziseven(z) (number is even)
|
|
zisodd(z) (number is odd)
|
|
ziszero(z) (number is zero)
|
|
zisneg(z) (number is negative)
|
|
zispos(z) (number is positive)
|
|
zisunit(z) (number is 1 or -1)
|
|
zisone(z) (number is 1)
|
|
zisnegone(z) (number is -1)
|
|
zistwo(z) (number is 2)
|
|
zisabstwo(z) (number is 2 or -2)
|
|
zisabsleone(z) (number is -1, 0 or 1)
|
|
zislezero(z) (number is <= 0)
|
|
zisleone(z) (number is <= 1)
|
|
zge16b(z) (number is >= 2^16)
|
|
zge24b(z) (number is >= 2^24)
|
|
zge31b(z) (number is >= 2^31)
|
|
zge32b(z) (number is >= 2^32)
|
|
zge64b(z) (number is >= 2^64)
|
|
|
|
Typically the largest unsigned long is typedefed to FULL. The following
|
|
macros are useful in dealing with this data type:
|
|
|
|
MAXFULL (largest positive FULL value)
|
|
MAXUFULL (largest unsigned FULL value)
|
|
zgtmaxfull(z) (number is > MAXFULL)
|
|
zgtmaxufull(z) (number is > MAXUFULL)
|
|
zgtmaxlong(z) (number is > MAXLONG, largest long value)
|
|
zgtmaxulong(z) (number is > MAXULONG, largest unsigned long value)
|
|
|
|
If zgtmaxufull(z) is false, then one may quickly convert the absolute
|
|
value of number into a full with the macro:
|
|
|
|
ztofull(z) (convert abs(number) to FULL)
|
|
ztoulong(z) (convert abs(number) to an unsigned long)
|
|
ztolong(z) (convert abs(number) to a long)
|
|
|
|
If the value is too large for ztofull(), ztoulong() or ztolong(), only
|
|
the low order bits converted.
|
|
|
|
There are two types of comparisons you can make on ZVALUEs. This is whether
|
|
or not they are equal, or the ordering on size of the numbers. The zcmp
|
|
function tests whether two ZVALUEs are equal, returning TRUE if they differ.
|
|
The zrel function tests the relative sizes of two ZVALUEs, returning -1 if
|
|
the first one is smaller, 0 if they are the same, and 1 if the first one
|
|
is larger.
|
|
|
|
---------------
|
|
USING FRACTIONS
|
|
---------------
|
|
|
|
The arbitrary precision fractional routines define a structure called NUMBER.
|
|
This is defined in qmath.h. A NUMBER contains two ZVALUEs for the numerator
|
|
and denominator of a fraction, and a count of the number of uses there are
|
|
for this NUMBER. The numerator and denominator are always in lowest terms,
|
|
and the sign of the number is contained in the numerator. The denominator
|
|
is always positive. If the NUMBER is an integer, the denominator has the
|
|
value 1.
|
|
|
|
Unlike ZVALUEs, NUMBERs are passed using pointers, and pointers to them are
|
|
returned by functions. So the basic type for using fractions is not really
|
|
(NUMBER), but is (NUMBER *). NUMBERs are allocated using the qalloc routine.
|
|
This returns a pointer to a number which has the value 1. Because of the
|
|
special property of a ZVALUE of 1, the numerator and denominator of this
|
|
returned value can simply be overwritten with new ZVALUEs without needing
|
|
to free them first. The following illustrates this:
|
|
|
|
NUMBER *q;
|
|
|
|
q = qalloc();
|
|
itoz(55L, &q->num);
|
|
|
|
A better way to create NUMBERs with particular values is to use the itoq,
|
|
iitoq, or atoq functions. Using itoq makes a long value into a NUMBER,
|
|
using iitoq makes a pair of longs into the numerator and denominator of a
|
|
NUMBER (reducing them first if needed), and atoq converts a string representing
|
|
a number into the corresponding NUMBER. The atoq function accepts input in
|
|
integral, fractional, real, or exponential formats. Examples of allocating
|
|
numbers are:
|
|
|
|
NUMBER *q1, *q2, *q3;
|
|
|
|
q1 = itoq(66L);
|
|
q2 = iitoq(2L, 3L);
|
|
q3 = atoq("456.78");
|
|
|
|
Also unlike ZVALUEs, NUMBERs are quickly copied. This is because they contain
|
|
a link count, which is the number of pointers there are to the NUMBER. The
|
|
qlink macro is used to copy a pointer to a NUMBER, and simply increments
|
|
the link count and returns the same pointer. Since it is a macro, the
|
|
argument should not be a function call, but a real pointer variable. The
|
|
qcopy routine will actually make a new copy of a NUMBER, with a new link
|
|
count of 1. This is not usually needed.
|
|
|
|
NUMBERs are deleted using the qfree routine. This decrements the link count
|
|
in the NUMBER, and if it reaches zero, then it will deallocate both of
|
|
the ZVALUEs contained within the NUMBER, and then puts the NUMBER structure
|
|
onto a free list for quick reuse. The following is an example of allocating
|
|
NUMBERs, copying them, adding them, and finally deleting them again.
|
|
|
|
NUMBER *q1, *q2, *q3;
|
|
|
|
q1 = itoq(111L);
|
|
q2 = qlink(q1);
|
|
q3 = qqadd(q1, q2);
|
|
qfree(q1);
|
|
qfree(q2);
|
|
qfree(q3);
|
|
|
|
Because of the passing of pointers and the ability to copy numbers easily,
|
|
you might wish to use the rational number routines even for integral
|
|
calculations. They might be slightly slower than the raw integral routines,
|
|
but are more convenient to program with.
|
|
|
|
The prototypes for the fractional routines are defined in qmath.h.
|
|
Many of the definitions for integer functions parallel the ones defined
|
|
in zmath.h. But there are also functions used only for fractions.
|
|
Examples of these are qnum to return the numerator, qden to return the
|
|
denominator, qint to return the integer part of, qfrac to return the
|
|
fractional part of, and qinv to invert a fraction.
|
|
|
|
There are some transcendental functions in the link library, such as sin
|
|
and cos. These cannot be evaluated exactly as fractions. Therefore,
|
|
they accept another argument which tells how accurate you want the result.
|
|
This is an "epsilon" value, and the returned value will be within that
|
|
quantity of the correct value. This is usually an absolute difference,
|
|
but for some functions (such as exp), this is a relative difference.
|
|
For example, to calculate sin(0.5) to 100 decimal places, you could do:
|
|
|
|
NUMBER *q, *ans, *epsilon;
|
|
|
|
q = atoq("0.5");
|
|
epsilon = atoq("1e-100");
|
|
ans = qsin(q, epsilon);
|
|
|
|
There are many convenience macros similar to the ones for ZVALUEs which can
|
|
give quick information about NUMBERs. In addition, there are some new ones
|
|
applicable to fractions. These are all defined in qmath.h. Some of these
|
|
macros are:
|
|
|
|
qiszero(q) (number is zero)
|
|
qisneg(q) (number is negative)
|
|
qispos(q) (number is positive)
|
|
qisint(q) (number is an integer)
|
|
qisfrac(q) (number is fractional)
|
|
qisunit(q) (number is 1 or -1)
|
|
qisone(q) (number is 1)
|
|
qisnegone(q) (number is -1)
|
|
qistwo(q) (number is 2)
|
|
qiseven(q) (number is an even integer)
|
|
qisodd(q) (number is an odd integer)
|
|
qistwopower(q) (number is a power of 2 >= 1)
|
|
|
|
The comparisons for NUMBERs are similar to the ones for ZVALUEs. You use the
|
|
qcmp and qrel functions.
|
|
|
|
There are four predefined values for fractions. You should qlink them when
|
|
you want to use them. These are _qzero_, _qone_, _qnegone_, and _qonehalf_.
|
|
These have the values 0, 1, -1, and 1/2. An example of using them is:
|
|
|
|
NUMBER *q1, *q2;
|
|
|
|
q1 = qlink(&_qonehalf_);
|
|
q2 = qlink(&_qone_);
|
|
|
|
---------------------
|
|
USING COMPLEX NUMBERS
|
|
---------------------
|
|
|
|
The arbitrary precision complex arithmetic routines define a structure
|
|
called COMPLEX. This is defined in cmath.h. This contains two NUMBERs
|
|
for the real and imaginary parts of a complex number, and a count of the
|
|
number of links there are to this COMPLEX number.
|
|
|
|
The complex number routines work similarly to the fractional routines.
|
|
You can allocate a COMPLEX structure using comalloc (NOT calloc!).
|
|
You can construct a COMPLEX number with desired real and imaginary
|
|
fractional parts using qqtoc. You can copy COMPLEX values using clink
|
|
which increments the link count. And you free a COMPLEX value using cfree.
|
|
The following example illustrates this:
|
|
|
|
NUMBER *q1, *q2;
|
|
COMPLEX *c1, *c2, *c3;
|
|
|
|
q1 = itoq(3L);
|
|
q2 = itoq(4L);
|
|
c1 = qqtoc(q1, q2);
|
|
qfree(q1);
|
|
qfree(q2);
|
|
c2 = clink(c1);
|
|
c3 = cmul(c1, c2);
|
|
cfree(c1);
|
|
cfree(c2);
|
|
cfree(c3);
|
|
|
|
As a shortcut, when you want to manipulate a COMPLEX value by a real value,
|
|
you can use the caddq, csubq, cmulq, and cdivq routines. These accept one
|
|
COMPLEX value and one NUMBER value, and produce a COMPLEX value.
|
|
|
|
There is no direct routine to convert a string value into a COMPLEX value.
|
|
But you can do this yourself by converting two strings into two NUMBERS,
|
|
and then using the qqtoc routine.
|
|
|
|
COMPLEX values are always returned from these routines. To split out the
|
|
real and imaginary parts into normal NUMBERs, you can simply qlink the
|
|
two components, as shown in the following example:
|
|
|
|
COMPLEX *c;
|
|
NUMBER *rp, *ip;
|
|
|
|
c = calloc();
|
|
rp = qlink(c->real);
|
|
ip = qlink(c->imag);
|
|
|
|
There are many macros for checking quick things about complex numbers,
|
|
similar to the ZVALUE and NUMBER macros. In addition, there are some
|
|
only used for complex numbers. Examples of macros are:
|
|
|
|
cisreal(c) (number is real)
|
|
cisimag(c) (number is pure imaginary)
|
|
ciszero(c) (number is zero)
|
|
cisnegone(c) (number is -1)
|
|
cisone(c) (number is 1)
|
|
cisrunit(c) (number is 1 or -1)
|
|
cisiunit(c) (number is i or -i)
|
|
cisunit(c) (number is 1, -1, i, or -i)
|
|
cistwo(c) (number is 2)
|
|
cisint(c) (number is has integer real and imaginary parts)
|
|
ciseven(c) (number is has even real and imaginary parts)
|
|
cisodd(c) (number is has odd real and imaginary parts)
|
|
|
|
There is only one comparison you can make for COMPLEX values, and that is
|
|
for equality. The ccmp function returns TRUE if two complex numbers differ.
|
|
|
|
There are three predefined values for complex numbers. You should clink
|
|
them when you want to use them. They are _czero_, _cone_, and _conei_.
|
|
These have the values 0, 1, and i.
|
|
|
|
----------------
|
|
LAST THINGS LAST
|
|
----------------
|
|
|
|
If you wish, when you are all doen you can call libcalc_call_me_last()
|
|
to free a small amount of storage associated with the libcalc_call_me_first()
|
|
call. This is not required, but is does bring things to a closure.
|
|
|
|
The function libcalc_call_me_last() takes no args and returns void. You
|
|
need call libcalc_call_me_last() only once.
|
|
|
|
## Copyright (C) 1999 David I. Bell and Landon Curt Noll
|
|
##
|
|
## Calc is open software; you can redistribute it and/or modify it under
|
|
## the terms of the version 2.1 of the GNU Lesser General Public License
|
|
## as published by the Free Software Foundation.
|
|
##
|
|
## Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
## Public License for more details.
|
|
##
|
|
## A copy of version 2.1 of the GNU Lesser General Public License is
|
|
## distributed with calc under the filename COPYING-LGPL. You should have
|
|
## received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
##
|
|
## @(#) $Revision: 29.1 $
|
|
## @(#) $Id: LIBRARY,v 29.1 1999/12/14 09:15:29 chongo Exp $
|
|
## @(#) $Source: /usr/local/src/cmd/calc/RCS/LIBRARY,v $
|
|
##
|
|
## Under source code control: 1993/07/30 19:44:49
|
|
## File existed as early as: 1993
|
|
##
|
|
## chongo <was here> /\oo/\ http://reality.sgi.com/chongo/
|
|
## Share and enjoy! :-) http://reality.sgi.com/chongo/tech/comp/calc/
|