Release calc version 2.10.2t30

This commit is contained in:
Landon Curt Noll
1996-07-06 04:17:00 -07:00
commit 4618313a82
388 changed files with 85904 additions and 0 deletions

95
BUGS Normal file
View File

@@ -0,0 +1,95 @@
If you notice something wrong, strange or broken, try rereading:
README.FIRST
README
BUGS (in particular the bottom problems or mis-features section)
If that does not help, cd to the calc source directory and try:
make check
Look at the end of the output, it should say something like:
9999: passed all tests /\../\
If it does not, then something is really broken!
If you made and modifications to calc beyond the simple Makefile
configuration, try backing them out and see if things get better.
Check to see if the version of calc you are using is current. Calc
distributions may be obtained from the official calc repository:
ftp://ftp.uu.net/pub/calc
If you are an alpha or beta tester, you may have a special pre-released
version that is more advanced than what is in the ftp archive.
=-=
If you have tried all of the above and things still are not right,
then it may be time to send in a bug report. You can send bug reports to:
calc-tester@postofc.corp.sgi.com
When you send your report, please include the following information:
* a description of the problem
* the version of calc you are using (if you cannot get calc
it to run, then send us the 4 #define lines from version.c)
* if you modified calc from an official patch, send me the mods you made
* the type of system you were using
* the type of compiler you were using
* cd to the calc source directory, and type:
make debug > debug.out 2>&1 (sh, ksh, bash users)
make debug >& debug.out (csh, tcsh users)
and send the contents of the 'debug.out' file.
Stack traces from core dumps are useful to send as well.
=-=
The official calc repository is located in:
ftp://ftp.uu.net/pub/calc
If you don't have ftp access to that site, or if your version is more
recent than what has been released to the ftp archive, you may, as a
last resort, send EMail to:
chongo@toad.com
Indicate the version you have and that you would like a more up to date version.
=-=
Send any comments, suggestions and most importantly, fixes (in the form
of a context diff patch) to:
calc-tester@postofc.corp.sgi.com
=-=
Known problems or mis-features:
* In calc2.10.2t3, when scan() reads characters from stdin, they
are not echoed. This also happens with fgets(files(0)) and
fgetline(files(0)). Reports indicate that this did not happen in
calc.2.10.1t20 but did in 2.10.2t0.
* Many of LIBRARY, LIMITS and SEE ALSO sections of help files
for builtins are either inconsistent or missing information.
* The functions filepos2z() and z2filepos() do not work (or
worse do not compile) when FILEPOS is 64 bits long.
* There is some places in the source with obscure variable names
and not much in the way of comments. We need some major cleanup
and documentation.

1618
CHANGES Normal file

File diff suppressed because it is too large Load Diff

436
LIBRARY Normal file
View File

@@ -0,0 +1,436 @@
USING THE ARBITRARY PRECISION ROUTINES IN A C PROGRAM
Part of the calc release consists of an arbitrary precision math library.
This 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 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.
------------------
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 library itself (and the lint library
llib-lcalc.ln, if made) 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 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 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) {
/* handle error */
printf("Ouch: %s\n", calc_error);
}
calc_jmp = 1;
---------------
OUTPUT ROUTINES
---------------
The output from the routines in the 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 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.

2967
Makefile Normal file

File diff suppressed because it is too large Load Diff

68
README Normal file
View File

@@ -0,0 +1,68 @@
# Copyright (c) 1994 David I. Bell
# Permission is granted to use, distribute, or modify this source,
# provided that this copyright notice remains intact.
#
# Arbitrary precision calculator.
I am allowing this calculator to be freely distributed for personal uses.
Like all multi-precision programs, you should not depend absolutely on
its results, since bugs in such programs can be insidious and only rarely
show up.
-dbell-
p.s. By Landon Curt Noll:
Building calc in 3 easy steps:
1) Look at the makefile, and adjust it to suit your needs.
Here are some Makefile hints:
In the past, some people have had to adjust the VARARG or
TERMCONTROL because the Makefile cannot always guess
correctly for certain systems. You may need to play with
these values if you experience problems.
The default compiler used is 'cc'. The default compiler flag
is '-O'. If you have gcc, or gcc v2 (or better) you should use
that instead. Some compilers allow for optimization beyond
just -O (gcc v2 has -O2, mips cc has -O3). You should select
the best flag for speed optimization. Calc can be cpu intensive
so selecting a quality compiler and good optimization level can
really pay off.
2) build calc:
make all
3) test calc:
make check
==>>>If you run into problems, follow the instructions in the BUGS file<<<==
=-=
For further reading:
LIBRARY
explains how programs can use libcalc.a to take advantage
of the calc multi-precision routines.
help/todo
current wish list for calc
CHANGES
recent changes to calc
BUGS
known bugs, mis-features and how to report problems
help/full
full set of calc documentation
=-=
David I. Bell dbell@auug.org.au
chongo@toad.com <Landon Curt Noll -- chongo@toad.com> /\../\

52
README.FIRST Normal file
View File

@@ -0,0 +1,52 @@
Dear alpha tester,
Thanks for taking the time to try out this alpha version of calc! We are
interested in any/all feedback that you may have on this version. In
particular we would like to hear about:
* compile problems
* regression test problems (try: make check)
* compiler warnings
* special compile flags/options that you needed
* Makefile problems
* help file problems
* misc nits and typos
We would like to offer a clean compile across a wide verity of platforms,
so if you can test on several, so much the better!
Calc distributions may be obtained from:
ftp://ftp.uu.net/pub/calc
If you don't have ftp access to that site, or if you do not find a more
recent version (you may have a special pre-released version that is
more advanced than what is in the ftp archive) send EMail to:
chongo@toad.com
Indicate the version you have and that you would like a more up
to date version.
=-=
Misc items TODO before Beta release:
* improve the coverage in the 'SEE ALSO' help file lists
* where reasonable, be sure that regress.cal tests builtin functions
* add the Blum-Blum-Shub random() generator code
* add code to allow of the reading, writing and processing of binary data
* add shs, shs-1 and md5 hashing functions. Use align32.h.
* add mod h*2^n+/-1 function for integers
* be sure that CHANGES is up to date,
look over the help/todo file and update as needed,
revisit issues in the BUGS file and
change this file :-)
* clean the source code and document it better

448
addop.c Normal file
View File

@@ -0,0 +1,448 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Add opcodes to a function being compiled.
*/
#include "calc.h"
#include "opcodes.h"
#include "string.h"
#include "func.h"
#include "token.h"
#include "label.h"
#include "symbol.h"
#define FUNCALLOCSIZE 20 /* reallocate size for functions */
#define OPCODEALLOCSIZE 100 /* reallocate size for opcodes in functions */
static long maxopcodes; /* number of opcodes available */
static long newindex; /* index of new function */
static long oldop; /* previous opcode */
static long debugline; /* line number of latest debug opcode */
static long funccount; /* number of functions */
static long funcavail; /* available number of functions */
static FUNC *functemplate; /* function definition template */
static FUNC **functions; /* table of functions */
static STRINGHEAD funcnames; /* function names */
/*
* Initialize the table of user defined functions.
*/
void
initfunctions(void)
{
initstr(&funcnames);
maxopcodes = OPCODEALLOCSIZE;
functemplate = (FUNC *) malloc(funcsize(maxopcodes));
if (functemplate == NULL) {
math_error("Cannot allocate function template");
/*NOTREACHED*/
}
functions = (FUNC **) malloc(sizeof(FUNC *) * FUNCALLOCSIZE);
if (functions == NULL) {
math_error("Cannot allocate function table");
/*NOTREACHED*/
}
funccount = 0;
funcavail = FUNCALLOCSIZE;
}
/*
* Show the list of user defined functions.
*/
void
showfunctions(void)
{
FUNC **fpp; /* pointer into function table */
FUNC *fp; /* current function */
if (funccount == 0) {
printf("No user functions defined.\n");
return;
}
printf("Name Arguments\n");
printf("---- ---------\n");
for (fpp = &functions[funccount - 1]; fpp >= functions; fpp--) {
fp = *fpp;
if (fp == NULL)
continue;
printf("%-12s %-2d\n", fp->f_name, fp->f_paramcount);
}
printf("\n");
}
/*
* Initialize a function for definition.
* Newflag is TRUE if we should allocate a new function structure,
* instead of the usual overwriting of the template function structure.
* The new structure is returned in the global curfunc variable.
*
* given:
* name name of function
* newflag TRUE if need new structure
*/
void
beginfunc(char *name, BOOL newflag)
{
register FUNC *fp; /* current function */
newindex = adduserfunc(name);
maxopcodes = OPCODEALLOCSIZE;
fp = functemplate;
if (newflag) {
fp = (FUNC *) malloc(funcsize(maxopcodes));
if (fp == NULL) {
math_error("Cannot allocate temporary function");
/*NOTREACHED*/
}
}
fp->f_next = NULL;
fp->f_localcount = 0;
fp->f_opcodecount = 0;
fp->f_savedvalue.v_type = V_NULL;
fp->f_name = namestr(&funcnames, newindex);
curfunc = fp;
initlocals();
initlabels();
oldop = OP_NOP;
debugline = 0;
errorcount = 0;
}
/*
* Commit the just defined function for use.
* This replaces any existing definition for the function.
* This should only be called for normal user-defined functions.
*/
void
endfunc(void)
{
register FUNC *fp; /* function just finished */
unsigned long size; /* size of just created function */
checklabels();
if (errorcount) {
printf("\"%s\": %ld error%s\n", curfunc->f_name, errorcount,
((errorcount == 1) ? "" : "s"));
return;
}
size = funcsize(curfunc->f_opcodecount);
fp = (FUNC *) malloc(size);
if (fp == NULL) {
math_error("Cannot commit function");
/*NOTREACHED*/
}
memcpy((char *) fp, (char *) curfunc, size);
if (curfunc != functemplate)
free(curfunc);
if (conf->traceflags & TRACE_FNCODES) {
dumpnames = TRUE;
for (size = 0; size < fp->f_opcodecount; ) {
printf("%ld: ", (long)size);
size += dumpop(&fp->f_opcodes[size]);
}
}
if (functions[newindex]) {
free(functions[newindex]);
fprintf(stderr, "**** %s() has been redefined\n", fp->f_name);
}
functions[newindex] = fp;
objuncache();
if (inputisterminal())
printf("\"%s\" defined\n", fp->f_name);
}
/*
* Find the user function with the specified name, and return its index.
* If the function does not exist, its name is added to the function table
* and an error will be generated when it is called if it is still undefined.
*
* given:
* name name of function
*/
long
adduserfunc(char *name)
{
long index; /* index of function */
index = findstr(&funcnames, name);
if (index >= 0)
return index;
if (funccount >= funcavail) {
functions = (FUNC **) realloc(functions,
sizeof(FUNC *) * (funcavail + FUNCALLOCSIZE));
if (functions == NULL) {
math_error("Failed to reallocate function table");
/*NOTREACHED*/
}
funcavail += FUNCALLOCSIZE;
}
if (addstr(&funcnames, name) == NULL) {
math_error("Cannot save function name");
/*NOTREACHED*/
}
index = funccount++;
functions[index] = NULL;
return index;
}
/*
* Clear any optimization that may be done for the next opcode.
* This is used when defining a label.
*/
void
clearopt(void)
{
oldop = OP_NOP;
debugline = 0;
}
/*
* Find a function structure given its index.
*/
FUNC *
findfunc(long index)
{
if ((unsigned long) index >= funccount) {
math_error("Undefined function");
/*NOTREACHED*/
}
return functions[index];
}
/*
* Return the name of a function given its index.
*/
char *
namefunc(long index)
{
return namestr(&funcnames, index);
}
/*
* Let a matrix indexing operation know that it will be treated as a write
* reference instead of just as a read reference.
*/
void
writeindexop(void)
{
if (oldop == OP_INDEXADDR)
curfunc->f_opcodes[curfunc->f_opcodecount - 1] = TRUE;
}
/*
* Add an opcode to the current function being compiled.
* Note: This can change the curfunc global variable when the
* function needs expanding.
*/
void
addop(long op)
{
register FUNC *fp; /* current function */
NUMBER *q;
fp = curfunc;
if ((fp->f_opcodecount + 5) >= maxopcodes) {
maxopcodes += OPCODEALLOCSIZE;
fp = (FUNC *) malloc(funcsize(maxopcodes));
if (fp == NULL) {
math_error("cannot malloc function");
/*NOTREACHED*/
}
memcpy((char *) fp, (char *) curfunc,
funcsize(curfunc->f_opcodecount));
if (curfunc != functemplate)
free(curfunc);
curfunc = fp;
}
/*
* Check the current opcode against the previous opcode and try to
* slightly optimize the code depending on the various combinations.
*/
if (op == OP_GETVALUE) {
switch (oldop) {
case OP_NUMBER: case OP_ZERO: case OP_ONE: case OP_IMAGINARY:
case OP_GETEPSILON: case OP_SETEPSILON: case OP_STRING:
case OP_UNDEF: case OP_GETCONFIG: case OP_SETCONFIG:
return;
case OP_DUPLICATE:
fp->f_opcodes[fp->f_opcodecount - 1] = OP_DUPVALUE;
oldop = OP_DUPVALUE;
return;
case OP_FIADDR:
fp->f_opcodes[fp->f_opcodecount - 1] = OP_FIVALUE;
oldop = OP_FIVALUE;
return;
case OP_GLOBALADDR:
fp->f_opcodes[fp->f_opcodecount - 2] = OP_GLOBALVALUE;
oldop = OP_GLOBALVALUE;
return;
case OP_LOCALADDR:
fp->f_opcodes[fp->f_opcodecount - 2] = OP_LOCALVALUE;
oldop = OP_LOCALVALUE;
return;
case OP_PARAMADDR:
fp->f_opcodes[fp->f_opcodecount - 2] = OP_PARAMVALUE;
oldop = OP_PARAMVALUE;
return;
case OP_ELEMADDR:
fp->f_opcodes[fp->f_opcodecount - 2] = OP_ELEMVALUE;
oldop = OP_ELEMVALUE;
return;
}
}
if ((op == OP_NEGATE) && (oldop == OP_NUMBER)) {
q = constvalue(fp->f_opcodes[fp->f_opcodecount - 1]);
fp->f_opcodes[fp->f_opcodecount - 1] = addqconstant(qneg(q));
oldop = OP_NUMBER;
return;
}
if ((op == OP_POWER) && (oldop == OP_NUMBER)) {
if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 2L) == 0) {
fp->f_opcodecount--;
fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
oldop = OP_SQUARE;
return;
}
if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 4L) == 0) {
fp->f_opcodes[fp->f_opcodecount - 2] = OP_SQUARE;
fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
oldop = OP_SQUARE;
return;
}
}
if ((op == OP_POP) && (oldop == OP_ASSIGN)) { /* optimize */
fp->f_opcodes[fp->f_opcodecount - 1] = OP_ASSIGNPOP;
oldop = OP_ASSIGNPOP;
return;
}
/*
* No optimization possible, so store the opcode.
*/
fp->f_opcodes[fp->f_opcodecount] = op;
fp->f_opcodecount++;
oldop = op;
}
/*
* Add an opcode and and one integer argument to the current function
* being compiled.
*/
void
addopone(long op, long arg)
{
NUMBER *q;
switch (op) {
case OP_NUMBER:
q = constvalue(arg);
if (q == NULL)
break;
if (qiszero(q)) {
addop(OP_ZERO);
return;
}
if (qisone(q)) {
addop(OP_ONE);
return;
}
break;
case OP_DEBUG:
if ((conf->traceflags & TRACE_NODEBUG) || (arg == debugline))
return;
debugline = arg;
if (oldop == OP_DEBUG) {
curfunc->f_opcodes[curfunc->f_opcodecount - 1] = arg;
return;
}
break;
}
addop(op);
curfunc->f_opcodes[curfunc->f_opcodecount] = arg;
curfunc->f_opcodecount++;
}
/*
* Add an opcode and and two integer arguments to the current function
* being compiled.
*/
void
addoptwo(long op, long arg1, long arg2)
{
addop(op);
curfunc->f_opcodes[curfunc->f_opcodecount++] = arg1;
curfunc->f_opcodes[curfunc->f_opcodecount++] = arg2;
}
/*
* Add an opcode and a character pointer to the function being compiled.
*/
void
addopptr(long op, char *ptr)
{
char **ptraddr;
addop(op);
ptraddr = (char **) &curfunc->f_opcodes[curfunc->f_opcodecount];
*ptraddr = ptr;
curfunc->f_opcodecount += PTR_SIZE;
}
/*
* Add an opcode and an index and an argument count for a function call.
*/
void
addopfunction(long op, long index, int count)
{
long newop;
if ((op == OP_CALL) && ((newop = builtinopcode(index)) != OP_NOP)) {
if ((newop == OP_SETCONFIG) && (count == 1))
newop = OP_GETCONFIG;
if ((newop == OP_SETEPSILON) && (count == 0))
newop = OP_GETEPSILON;
if ((newop == OP_ABS) && (count == 1))
addop(OP_GETEPSILON);
addop(newop);
return;
}
addop(op);
curfunc->f_opcodes[curfunc->f_opcodecount++] = index;
curfunc->f_opcodes[curfunc->f_opcodecount++] = count;
}
/*
* Add a jump-type opcode and a label to the function being compiled.
*
* given:
* label label to be added
*/
void
addoplabel(long op, LABEL *label)
{
addop(op);
uselabel(label);
}
/* END CODE */

79
align32.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* align32 - determine if 32 bit accesses must be aligned
*
* This file was written by:
*
* Landon Curt Noll (chongo@toad.com) chongo <was here> /\../\
*
* This code has been placed in the public domain. Please do not
* copyright this code.
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
* CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
* NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <signal.h>
#include "longbits.h"
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
static void buserr(void); /* catch alignment errors */
MAIN
main(void)
{
char byte[2*sizeof(USB32)]; /* mis-alignment buffer */
USB32 *p; /* mis-alignment pointer */
int i;
#if defined(MUST_ALIGN32)
/* force alignment */
printf("#define MUST_ALIGN32\t%c* forced to align 32 bit values *%c\n",
'/', '/');
#else
/* setup to catch alignment bus errors */
signal(SIGBUS, buserr);
signal(SIGSEGV, buserr); /* some systems will generate SEGV instead! */
/* mis-align our long fetches */
for (i=0; i < sizeof(USB32); ++i) {
p = (USB32 *)(byte+i);
*p = i;
*p += 1;
}
/* if we got here, then we can mis-align longs */
printf("#undef MUST_ALIGN32\t%c* can mis-align 32 bit values *%c\n",
'/', '/');
#endif
exit(0);
}
/*
* buserr - catch an alignment error
*
* given:
* arg to keep ANSI C happy
*/
/*ARGSUSED*/
static void
buserr(int arg)
{
/* alignment is required */
printf("#define MUST_ALIGN32\t%c* must align 32 bit values *%c\n",
'/', '/');
exit(0);
}

64
alloc.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*/
#if !defined(ALLOC_H)
#define ALLOC_H
#include "have_malloc.h"
#include "have_newstr.h"
#include "have_string.h"
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#else
# if defined(__STDC__) && __STDC__ != 0
extern void *malloc();
extern void *realloc();
extern void free();
# else
extern char *malloc();
extern char *realloc();
extern void free();
# endif
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#else
# if defined(HAVE_NEWSTR)
extern void *memcpy();
extern void *memset();
# if defined(__STDC__) && __STDC__ != 0
extern size_t strlen();
# else
extern long strlen(); /* should be size_t, but old systems don't have it */
# endif
# else /* HAVE_NEWSTR */
extern void bcopy();
extern void bfill();
extern char *index();
# endif /* HAVE_NEWSTR */
extern char *strchr();
extern char *strcpy();
extern char *strncpy();
extern char *strcat();
extern int strcmp();
#endif
#if !defined(HAVE_NEWSTR)
#undef memcpy
#define memcpy(s1, s2, n) bcopy(s2, s1, n)
#undef memset
#define memset(s, c, n) bfill(s, n, c)
#undef strchr
#define strchr(s, c) index(s, c)
#endif /* HAVE_NEWSTR */
#endif /* !ALLOC_H */

477
assocfunc.c Normal file
View File

@@ -0,0 +1,477 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Association table routines.
* An association table is a type of value which can be "indexed" by
* one or more arbitrary values. Each element in the table is thus an
* association between a particular set of index values and a result value.
* The elements in an association table are stored in a hash table for
* quick access.
*/
#include "value.h"
#define MINHASHSIZE 31 /* minimum size of hash tables */
#define GROWHASHSIZE 50 /* approximate growth for hash tables */
#define CHAINLENGTH 10 /* desired number of elements on a hash chain */
#define ELEMSIZE(n) (sizeof(ASSOCELEM) + (sizeof(VALUE) * ((n) - 1)))
static ASSOCELEM *elemindex(ASSOC *ap, long index);
static BOOL compareindices(VALUE *v1, VALUE *v2, long dim);
static void resize(ASSOC *ap, long newsize);
static void assoc_elemfree(ASSOCELEM *ep);
/*
* Return the address of the value specified by normal indexing of
* an association. The create flag is TRUE if a value is going to be
* assigned into the specified indexing location. If create is FALSE and
* the index value doesn't exist, a pointer to a NULL value is returned.
*
* given:
* ap association to index into
* create whether to create the index value
* dim dimension of the indexing
* indices table of values being indexed by
*/
VALUE *
associndex(ASSOC *ap, BOOL create, long dim, VALUE *indices)
{
ASSOCELEM **listhead;
ASSOCELEM *ep;
static VALUE val;
QCKHASH hash;
int i;
if (dim <= 0) {
math_error("No dimensions for indexing association");
/*NOTREACHED*/
}
/*
* Calculate the hash value to use for this set of indices
* so that we can first select the correct hash chain, and
* also so we can quickly compare each element for a match.
*/
hash = (QCKHASH)0;
for (i = 0; i < dim; i++)
hash = hashvalue(&indices[i], hash);
/*
* Search the correct hash chain for the specified set of indices.
* If found, return the address of the found element's value.
*/
listhead = &ap->a_table[hash % ap->a_size];
for (ep = *listhead; ep; ep = ep->e_next) {
if ((ep->e_hash != hash) || (ep->e_dim != dim))
continue;
if (compareindices(ep->e_indices, indices, dim))
return &ep->e_value;
}
/*
* The set of indices was not found.
* Either return a pointer to a NULL value for a read reference,
* or allocate a new element in the list for a write reference.
*/
if (!create) {
val.v_type = V_NULL;
return &val;
}
ep = (ASSOCELEM *) malloc(ELEMSIZE(dim));
if (ep == NULL) {
math_error("Cannot allocate association element");
/*NOTREACHED*/
}
ep->e_dim = dim;
ep->e_hash = hash;
ep->e_value.v_type = V_NULL;
for (i = 0; i < dim; i++)
copyvalue(&indices[i], &ep->e_indices[i]);
ep->e_next = *listhead;
*listhead = ep;
ap->a_count++;
resize(ap, ap->a_count / CHAINLENGTH);
return &ep->e_value;
}
/*
* Search an association for the specified value starting at the
* specified index. Returns the element number (zero based) of the
* found value, or -1 if the value was not found.
*/
long
assocsearch(ASSOC *ap, VALUE *vp, long index)
{
ASSOCELEM *ep;
if (index < 0)
index = 0;
while (TRUE) {
ep = elemindex(ap, index);
if (ep == NULL)
return -1;
if (!comparevalue(&ep->e_value, vp))
return index;
index++;
}
}
/*
* Search an association backwards for the specified value starting at the
* specified index. Returns the element number (zero based) of the
* found value, or -1 if the value was not found.
*/
long
assocrsearch(ASSOC *ap, VALUE *vp, long index)
{
ASSOCELEM *ep;
if (index >= ap->a_count)
index = ap->a_count - 1;
while (TRUE) {
ep = elemindex(ap, index);
if (ep == NULL)
return -1;
if (!comparevalue(&ep->e_value, vp))
return index;
index--;
}
}
/*
* Return the address of an element of an association indexed by the
* double-bracket operation.
*
* given:
* ap association to index into
* index index of desired element
*/
static ASSOCELEM *
elemindex(ASSOC *ap, long index)
{
ASSOCELEM *ep;
int i;
if ((index < 0) || (index > ap->a_count))
return NULL;
/*
* This loop should be made more efficient by remembering
* previously requested locations within the association.
*/
for (i = 0; i < ap->a_size; i++) {
for (ep = ap->a_table[i]; ep; ep = ep->e_next) {
if (index-- == 0)
return ep;
}
}
return NULL;
}
/*
* Return the address of the value specified by double-bracket indexing
* of an association. Returns NULL if there is no such element.
*
* given:
* ap association to index into
* index index of desired element
*/
VALUE *
assocfindex(ASSOC *ap, long index)
{
ASSOCELEM *ep;
ep = elemindex(ap, index);
if (ep == NULL)
return NULL;
return &ep->e_value;
}
/*
* Compare two associations to see if they are identical.
* Returns TRUE if they are different.
*/
BOOL
assoccmp(ASSOC *ap1, ASSOC *ap2)
{
ASSOCELEM **table1;
ASSOCELEM *ep1;
ASSOCELEM *ep2;
long size1;
long size2;
QCKHASH hash;
long dim;
if (ap1 == ap2)
return FALSE;
if (ap1->a_count != ap2->a_count)
return TRUE;
table1 = ap1->a_table;
size1 = ap1->a_size;
size2 = ap2->a_size;
while (size1-- > 0) {
for (ep1 = *table1++; ep1; ep1 = ep1->e_next) {
hash = ep1->e_hash;
dim = ep1->e_dim;
for (ep2 = ap2->a_table[hash % size2]; ;
ep2 = ep2->e_next)
{
if (ep2 == NULL)
return TRUE;
if (ep2->e_hash != hash)
continue;
if (ep2->e_dim != dim)
continue;
if (compareindices(ep1->e_indices,
ep2->e_indices, dim))
break;
}
if (comparevalue(&ep1->e_value, &ep2->e_value))
return TRUE;
}
}
return FALSE;
}
/*
* Copy an association value.
*/
ASSOC *
assoccopy(ASSOC *oldap)
{
ASSOC *ap;
ASSOCELEM *oldep;
ASSOCELEM *ep;
ASSOCELEM **listhead;
int oldhi;
int i;
ap = assocalloc(oldap->a_count / CHAINLENGTH);
ap->a_count = oldap->a_count;
for (oldhi = 0; oldhi < oldap->a_size; oldhi++) {
for (oldep = oldap->a_table[oldhi]; oldep;
oldep = oldep->e_next)
{
ep = (ASSOCELEM *) malloc(ELEMSIZE(oldep->e_dim));
if (ep == NULL) {
math_error("Cannot allocate association element");
/*NOTREACHED*/
}
ep->e_dim = oldep->e_dim;
ep->e_hash = oldep->e_hash;
ep->e_value.v_type = V_NULL;
for (i = 0; i < ep->e_dim; i++)
copyvalue(&oldep->e_indices[i], &ep->e_indices[i]);
copyvalue(&oldep->e_value, &ep->e_value);
listhead = &ap->a_table[ep->e_hash % ap->a_size];
ep->e_next = *listhead;
*listhead = ep;
}
}
return ap;
}
/*
* Resize the hash table for an association to be the specified size.
* This is only actually done if the growth from the previous size is
* enough to make this worthwhile.
*/
static void
resize(ASSOC *ap, long newsize)
{
ASSOCELEM **oldtable;
ASSOCELEM **newtable;
ASSOCELEM **oldlist;
ASSOCELEM **newlist;
ASSOCELEM *ep;
int i;
if (newsize < ap->a_size + GROWHASHSIZE)
return;
newsize = (long) next_prime((FULL)newsize);
newtable = (ASSOCELEM **) malloc(sizeof(ASSOCELEM *) * newsize);
if (newtable == NULL) {
math_error("No memory to grow association");
/*NOTREACHED*/
}
for (i = 0; i < newsize; i++)
newtable[i] = NULL;
oldtable = ap->a_table;
oldlist = oldtable;
for (i = 0; i < ap->a_size; i++) {
while (*oldlist) {
ep = *oldlist;
*oldlist = ep->e_next;
newlist = &newtable[ep->e_hash % newsize];
ep->e_next = *newlist;
*newlist = ep;
}
oldlist++;
}
ap->a_table = newtable;
ap->a_size = newsize;
free((char *) oldtable);
}
/*
* Free an association element, along with any contained values.
*/
static void
assoc_elemfree(ASSOCELEM *ep)
{
int i;
for (i = 0; i < ep->e_dim; i++)
freevalue(&ep->e_indices[i]);
freevalue(&ep->e_value);
ep->e_dim = 0;
ep->e_next = NULL;
free((char *) ep);
}
/*
* Allocate a new association value with an initial hash table.
* The hash table size is set at specified (but at least a minimum size).
*/
ASSOC *
assocalloc(long initsize)
{
register ASSOC *ap;
int i;
if (initsize < MINHASHSIZE)
initsize = MINHASHSIZE;
ap = (ASSOC *) malloc(sizeof(ASSOC));
if (ap == NULL) {
math_error("No memory for association");
/*NOTREACHED*/
}
ap->a_count = 0;
ap->a_size = initsize;
ap->a_table = (ASSOCELEM **) malloc(sizeof(ASSOCELEM *) * initsize);
if (ap->a_table == NULL) {
free((char *) ap);
math_error("No memory for association");
/*NOTREACHED*/
}
for (i = 0; i < initsize; i++)
ap->a_table[i] = NULL;
return ap;
}
/*
* Free an association value, along with all of its elements.
*/
void
assocfree(ASSOC *ap)
{
ASSOCELEM **listhead;
ASSOCELEM *ep;
ASSOCELEM *nextep;
int i;
listhead = ap->a_table;
for (i = 0; i < ap->a_size; i++) {
nextep = *listhead;
*listhead = NULL;
while (nextep) {
ep = nextep;
nextep = ep->e_next;
assoc_elemfree(ep);
}
listhead++;
}
free((char *) ap->a_table);
ap->a_table = NULL;
free((char *) ap);
}
/*
* Print out an association along with the specified number of
* its elements. The elements are printed out in shortened form.
*/
void
assocprint(ASSOC *ap, long max_print)
{
ASSOCELEM *ep;
long index;
long i;
int savemode;
if (max_print <= 0) {
math_fmt("assoc (%ld element%s)", ap->a_count,
((ap->a_count == 1) ? "" : "s"));
return;
}
math_fmt("\n assoc (%ld element%s):\n", ap->a_count,
((ap->a_count == 1) ? "" : "s"));
for (index = 0; ((index < max_print) && (index < ap->a_count));
index++)
{
ep = elemindex(ap, index);
if (ep == NULL)
continue;
math_str(" [");
for (i = 0; i < ep->e_dim; i++) {
if (i)
math_chr(',');
savemode = math_setmode(MODE_FRAC);
printvalue(&ep->e_indices[i],
(PRINT_SHORT | PRINT_UNAMBIG));
math_setmode(savemode);
}
math_str("] = ");
printvalue(&ep->e_value, PRINT_SHORT | PRINT_UNAMBIG);
math_chr('\n');
}
if (max_print < ap->a_count)
math_str(" ...\n");
}
/*
* Compare two lists of index values to see if they are identical.
* Returns TRUE if they are the same.
*/
static BOOL
compareindices(VALUE *v1, VALUE *v2, long dim)
{
int i;
for (i = 0; i < dim; i++)
if (v1[i].v_type != v2[i].v_type)
return FALSE;
while (dim-- > 0)
if (comparevalue(v1++, v2++))
return FALSE;
return TRUE;
}
/* END CODE */

686
byteswap.c Normal file
View File

@@ -0,0 +1,686 @@
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "cmath.h"
#include "byteswap.h"
/*
* swap_b8_in_HALFs - swap 8 and if needed, 16 bits in an array of HALFs
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a HALF array to swap
* len - length of the src HALF array
*
* returns:
* pointer to where the swapped src has been put
*/
HALF *
swap_b8_in_HALFs(HALF *dest, HALF *src, LEN len)
{
LEN i;
/*
* allocate storage if needed
*/
if (dest == NULL) {
dest = alloc(len);
}
/*
* swap the array
*/
for (i=0; i < len; ++i, ++dest, ++src) {
SWAP_B8_IN_HALF(dest, src);
}
/*
* return the result
*/
return dest;
}
/*
* swap_b8_in_ZVALUE - swap 8 and if needed, 16 bits in a ZVALUE
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a ZVALUE to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a ZVALUE.
*/
ZVALUE *
swap_b8_in_ZVALUE(ZVALUE *dest, ZVALUE *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(ZVALUE));
if (dest == NULL) {
math_error("swap_b8_in_ZVALUE: swap_b8_in_ZVALUE: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b8_in_ZVALUE) and swap storage
*/
dest->v = swap_b8_in_HALFs(NULL, src->v, src->len);
} else {
/*
* swap storage
*/
if (dest->v != NULL) {
zfree(*dest);
}
dest->v = swap_b8_in_HALFs(NULL, src->v, src->len);
}
/*
* swap or copy the rest of the ZVALUE elements
*/
if (all) {
dest->len = (LEN)SWAP_B8_IN_LEN(&dest->len, &src->len);
dest->sign = (BOOL)SWAP_B8_IN_BOOL(&dest->sign, &src->sign);
} else {
dest->len = src->len;
dest->sign = src->sign;
}
/*
* return the result
*/
return dest;
}
/*
* swap_b8_in_NUMBER - swap 8 and if needed, 16 bits in a NUMBER
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a NUMBER to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a NUMBER.
*/
NUMBER *
swap_b8_in_NUMBER(NUMBER *dest, NUMBER *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(NUMBER));
if (dest == NULL) {
math_error("swap_b8_in_NUMBER: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b8_in_ZVALUE) and swap storage
*/
dest->num = *swap_b8_in_ZVALUE(NULL, &src->num, all);
dest->den = *swap_b8_in_ZVALUE(NULL, &src->den, all);
} else {
/*
* swap storage
*/
dest->num = *swap_b8_in_ZVALUE(&dest->num, &src->num, all);
dest->den = *swap_b8_in_ZVALUE(&dest->den, &src->den, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_B8_IN_LONG(&dest->links, &src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}
/*
* swap_b8_in_COMPLEX - swap 8 and if needed, 16 bits in a COMPLEX
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a COMPLEX to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a COMPLEX.
*/
COMPLEX *
swap_b8_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(COMPLEX));
if (dest == NULL) {
math_error("swap_b8_in_COMPLEX: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b8_in_ZVALUE) and swap storage
*/
dest->real = swap_b8_in_NUMBER(NULL, src->real, all);
dest->imag = swap_b8_in_NUMBER(NULL, src->imag, all);
} else {
/*
* swap storage
*/
dest->real = swap_b8_in_NUMBER(dest->real, src->real, all);
dest->imag = swap_b8_in_NUMBER(dest->imag, src->imag, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_B8_IN_LONG(&dest->links, &src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}
/*
* swap_b16_in_HALFs - swap 16 bits in an array of HALFs
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a HALF array to swap
* len - length of the src HALF array
*
* returns:
* pointer to where the swapped src has been put
*/
HALF *
swap_b16_in_HALFs(HALF *dest, HALF *src, LEN len)
{
LEN i;
/*
* allocate storage if needed
*/
if (dest == NULL) {
dest = alloc(len);
}
/*
* swap the array
*/
for (i=0; i < len; ++i, ++dest, ++src) {
SWAP_B16_IN_HALF(dest, src);
}
/*
* return the result
*/
return dest;
}
/*
* swap_b16_in_ZVALUE - swap 16 bits in a ZVALUE
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a ZVALUE to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a ZVALUE.
*/
ZVALUE *
swap_b16_in_ZVALUE(ZVALUE *dest, ZVALUE *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(ZVALUE));
if (dest == NULL) {
math_error("swap_b16_in_ZVALUE: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b16_in_ZVALUE) and swap storage
*/
dest->v = swap_b16_in_HALFs(NULL, src->v, src->len);
} else {
/*
* swap storage
*/
if (dest->v != NULL) {
zfree(*dest);
}
dest->v = swap_b16_in_HALFs(NULL, src->v, src->len);
}
/*
* swap or copy the rest of the ZVALUE elements
*/
if (all) {
dest->len = (LEN)SWAP_B16_IN_LEN(&dest->len, &src->len);
dest->sign = (BOOL)SWAP_B16_IN_BOOL(&dest->sign, &src->sign);
} else {
dest->len = src->len;
dest->sign = src->sign;
}
/*
* return the result
*/
return dest;
}
/*
* swap_b16_in_NUMBER - swap 16 bits in a NUMBER
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a NUMBER to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a NUMBER.
*/
NUMBER *
swap_b16_in_NUMBER(NUMBER *dest, NUMBER *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(NUMBER));
if (dest == NULL) {
math_error("swap_b16_in_NUMBER: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b16_in_ZVALUE) and swap storage
*/
dest->num = *swap_b16_in_ZVALUE(NULL, &src->num, all);
dest->den = *swap_b16_in_ZVALUE(NULL, &src->den, all);
} else {
/*
* swap storage
*/
dest->num = *swap_b16_in_ZVALUE(&dest->num, &src->num, all);
dest->den = *swap_b16_in_ZVALUE(&dest->den, &src->den, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_B16_IN_LONG(&dest->links, &src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}
/*
* swap_b16_in_COMPLEX - swap 16 bits in a COMPLEX
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a COMPLEX to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a COMPLEX.
*/
COMPLEX *
swap_b16_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(COMPLEX));
if (dest == NULL) {
math_error("swap_b16_in_COMPLEX: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_b16_in_ZVALUE) and swap storage
*/
dest->real = swap_b16_in_NUMBER(NULL, src->real, all);
dest->imag = swap_b16_in_NUMBER(NULL, src->imag, all);
} else {
/*
* swap storage
*/
dest->real = swap_b16_in_NUMBER(dest->real, src->real, all);
dest->imag = swap_b16_in_NUMBER(dest->imag, src->imag, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_B16_IN_LONG(&dest->links, &src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}
/*
* swap_HALF_in_ZVALUE - swap HALFs in a ZVALUE
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a ZVALUE to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a ZVALUE.
*/
ZVALUE *
swap_HALF_in_ZVALUE(ZVALUE *dest, ZVALUE *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(ZVALUE));
if (dest == NULL) {
math_error("swap_HALF_in_ZVALUE: Not enough memory");
/*NOTREACHED*/
}
/*
* copy storage because we are dealing with HALFs
*/
dest->v = (HALF *) zcopyval(*src, *dest);
} else {
/*
* copy storage because we are dealing with HALFs
*/
if (dest->v != NULL) {
zfree(*dest);
dest->v = alloc(src->len);
}
zcopyval(*src, *dest);
}
/*
* swap or copy the rest of the ZVALUE elements
*/
if (all) {
dest->len = (LEN)SWAP_HALF_IN_LEN(&dest->len, &src->len);
dest->sign = (BOOL)SWAP_HALF_IN_BOOL(&dest->sign, &src->sign);
} else {
dest->len = src->len;
dest->sign = src->sign;
}
/*
* return the result
*/
return dest;
}
/*
* swap_HALF_in_NUMBER - swap HALFs in a NUMBER
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a NUMBER to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a NUMBER.
*/
NUMBER *
swap_HALF_in_NUMBER(NUMBER *dest, NUMBER *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(NUMBER));
if (dest == NULL) {
math_error("swap_HALF_in_NUMBER: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_HALF_in_ZVALUE) and swap storage
*/
dest->num = *swap_HALF_in_ZVALUE(NULL, &src->num, all);
dest->den = *swap_HALF_in_ZVALUE(NULL, &src->den, all);
} else {
/*
* swap storage
*/
dest->num = *swap_HALF_in_ZVALUE(&dest->num, &src->num, all);
dest->den = *swap_HALF_in_ZVALUE(&dest->den, &src->den, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_HALF_IN_LONG(&dest->links,&src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}
/*
* swap_HALF_in_COMPLEX - swap HALFs in a COMPLEX
*
* given:
* dest - pointer to where the swapped src wil be put or
* NULL to allocate the storage
* src - pointer to a COMPLEX to swap
* all - TRUE => swap every element, FALSE => swap only the
* multiprecision storage
*
* returns:
* pointer to where the swapped src has been put
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) the elements of a COMPLEX.
*/
COMPLEX *
swap_HALF_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all)
{
/*
* allocate storage if needed
*/
if (dest == NULL) {
/*
* allocate the storage
*/
dest = malloc(sizeof(COMPLEX));
if (dest == NULL) {
math_error("swap_HALF_in_COMPLEX: Not enough memory");
/*NOTREACHED*/
}
/*
* allocate (by forcing swap_HALF_in_ZVALUE) and swap storage
*/
dest->real = swap_HALF_in_NUMBER(NULL, src->real, all);
dest->imag = swap_HALF_in_NUMBER(NULL, src->imag, all);
} else {
/*
* swap storage
*/
dest->real = swap_HALF_in_NUMBER(dest->real, src->real, all);
dest->imag = swap_HALF_in_NUMBER(dest->imag, src->imag, all);
}
/*
* swap or copy the rest of the NUMBER elements
*/
if (all) {
dest->links = (long)SWAP_HALF_IN_LONG(&dest->links,&src->links);
} else {
dest->links = src->links;
}
/*
* return the result
*/
return dest;
}

166
byteswap.h Normal file
View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(BYTESWAP_H)
#define BYTESWAP_H
#include "longbits.h"
/*
* SWAP_B8_IN_B16 - swap 8 bits in 16 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 16 bit value to swap
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) a 16 bit value.
*/
#define SWAP_B8_IN_B16(dest, src) ( \
*((USB16*)(dest)) = \
(((*((USB16*)(src))) << 8) | ((*((USB16*)(src))) >> 8)) \
)
/*
* SWAP_B16_IN_B32 - swap 16 bits in 32 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 32 bit value to swap
*/
#define SWAP_B16_IN_B32(dest, src) ( \
*((USB32*)(dest)) = \
(((*((USB32*)(src))) << 16) | ((*((USB32*)(src))) >> 16)) \
)
/*
* SWAP_B8_IN_B32 - swap 8 & 16 bits in 32 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 32 bit value to swap
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) a 32 bit value.
*/
#define SWAP_B8_IN_B32(dest, src) ( \
SWAP_B16_IN_B32(dest, src), \
(*((USB32*)(dest)) = \
((((*((USB32*)(dest))) & (USB32)0xff00ff00) >> 8) | \
(((*((USB32*)(dest))) & (USB32)0x00ff00ff) << 8))) \
)
#if defined(HAVE_B64)
/*
* SWAP_B32_IN_B64 - swap 32 bits in 64 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*/
#define SWAP_B32_IN_B64(dest, src) ( \
*((USB64*)(dest)) = \
(((*((USB64*)(src))) << 32) | ((*((USB64*)(src))) >> 32)) \
)
/*
* SWAP_B16_IN_B64 - swap 16 & 32 bits in 64 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*/
#define SWAP_B16_IN_B64(dest, src) ( \
SWAP_B32_IN_B64(dest, src), \
(*((USB64*)(dest)) = \
((((*((USB64*)(dest))) & (USB64)0xffff0000ffff0000) >> 16) | \
(((*((USB64*)(dest))) & (USB64)0x0000ffff0000ffff) << 16))) \
)
/*
* SWAP_B8_IN_B64 - swap 16 & 32 bits in 64 bits
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) a 64 bit value.
*/
#define SWAP_B8_IN_B64(dest, src) ( \
SWAP_B16_IN_B64(dest, src), \
(*((USB64*)(dest)) = \
((((*((USB64*)(dest))) & (USB64)0xff00ff00ff00ff00) >> 8) | \
(((*((USB64*)(dest))) & (USB64)0x00ff00ff00ff00ff) << 8))) \
)
#else /* HAVE_B64 */
/*
* SWAP_B32_IN_B64 - swap 32 bits in 64 bits (simulated by 2 32 bit values)
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*/
#define SWAP_B32_IN_B64(dest, src) ( \
((USB32*)(dest))[1] = ((USB32*)(dest))[0], \
((USB32*)(dest))[0] = ((USB32*)(dest))[1] \
)
/*
* SWAP_B16_IN_B64 - swap 16 & 32 bits in 64 bits (simulated by 2 32 bit vals)
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*/
#define SWAP_B16_IN_B64(dest, src) ( \
SWAP_B16_IN_B32(((USB32*)dest)+1, ((USB32*)src)), \
SWAP_B16_IN_B32(((USB32*)dest), ((USB32*)src)+1) \
)
/*
* SWAP_B8_IN_B64 - swap 16 & 32 bits in 64 bits (simulated by 2 32 bit vals)
*
* dest - pointer to where the swapped src wil be put
* src - pointer to a 64 bit value to swap
*
* This macro will either switch to the opposite byte sex (Big Endian vs.
* Little Endian) a 64 bit value.
*/
#define SWAP_B8_IN_B64(dest, src) ( \
SWAP_B8_IN_B32(((USB32*)dest)+1, ((USB32*)src)), \
SWAP_B8_IN_B32(((USB32*)dest), ((USB32*)src)+1) \
)
#endif /* HAVE_B64 */
#if LONG_BITS == 64
#define SWAP_B32_IN_LONG(dest, src) SWAP_B32_IN_B64(dest, src)
#define SWAP_B16_IN_LONG(dest, src) SWAP_B16_IN_B64(dest, src)
#define SWAP_B8_IN_LONG(dest, src) SWAP_B8_IN_B64(dest, src)
#else /* LONG_BITS == 64 */
#define SWAP_B32_IN_LONG(dest, src) SWAP_B32_IN_B32(dest, src)
#define SWAP_B16_IN_LONG(dest, src) SWAP_B16_IN_B32(dest, src)
#define SWAP_B8_IN_LONG(dest, src) SWAP_B8_IN_B32(dest, src)
#endif /* LONG_BITS == 64 */
#endif /* !BYTESWAP_H */

441
calc.c Normal file
View File

@@ -0,0 +1,441 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Arbitrary precision calculator.
*/
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
#define CALC_C
#include "calc.h"
#include "hist.h"
#include "func.h"
#include "opcodes.h"
#include "conf.h"
#include "token.h"
#include "symbol.h"
#include "have_uid_t.h"
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include "have_stdlib.h"
#if defined(HAVE_STDLIB_H)
#include <stdlib.h>
#endif
/*
* in case we do not have certain .h files
*/
#if !defined(HAVE_STDLIB_H) && !defined(HAVE_UNISTD_H)
#if !defined(HAVE_UID_T) && !defined(_UID_T)
typedef unsigned short uid_t;
#endif
extern char *getenv();
extern uid_t geteuid();
#endif
/*
* Common definitions
*/
int abortlevel; /* current level of aborts */
BOOL inputwait; /* TRUE if in a terminal input wait */
jmp_buf jmpbuf; /* for errors */
int start_done = FALSE; /* TRUE => start up processing finished */
extern int isatty(int tty); /* TRUE if fd is a tty */
static int p_flag = FALSE; /* TRUE => pipe mode */
static int q_flag = FALSE; /* TRUE => don't execute rc files */
static int u_flag = FALSE; /* TRUE => unbuffer stdin and stdout */
/*
* global permissions
*/
int allow_read = TRUE; /* FALSE => may not open any files for reading */
int allow_write = TRUE; /* FALSE => may not open any files for writing */
int allow_exec = TRUE; /* FALSE => may not execute any commands */
char *calcpath; /* $CALCPATH or default */
char *calcrc; /* $CALCRC or default */
char *calcbindings; /* $CALCBINDINGS or default */
char *home; /* $HOME or default */
static char *pager; /* $PAGER or default */
char *shell; /* $SHELL or default */
int stdin_tty = TRUE; /* TRUE if stdin is a tty */
int post_init = FALSE; /* TRUE setjmp for math_error is readready */
/*
* some help topics are symbols, so we alias them to nice filenames
*/
static struct help_alias {
char *topic;
char *filename;
} halias[] = {
{"=", "assign"},
{"%", "mod"},
{"//", "quo"},
{NULL, NULL}
};
NUMBER *epsilon_default; /* default allowed error for float calcs */
static void intint(int arg); /* interrupt routine */
static void initenv(void); /* initialize environment vars */
extern void file_init(void);
extern void zio_init(void);
char cmdbuf[MAXCMD+1]; /* command line expression */
/*
* Top level calculator routine.
*/
MAIN
main(int argc, char **argv)
{
static char *str; /* current option string or expression */
int want_defhelp = 0; /* 1=> we only want the default help */
long i;
char *p;
/*
* parse args
*/
argc--;
argv++;
while ((argc > 0) && (**argv == '-')) {
for (str = &argv[0][1]; *str; str++) switch (*str) {
case 'h':
want_defhelp = 1;
break;
case 'm':
if (argv[0][2]) {
p = &argv[0][2];
} else if (argc > 1) {
p = argv[1];
argc--;
argv++;
} else {
fprintf(stderr, "-m requires an arg\n");
exit(1);
}
if (p[1] != '\0' || *p < '0' || *p > '7') {
fprintf(stderr, "unknown -m arg\n");
exit(1);
}
allow_read = (((*p-'0') & 04) > 0);
allow_write = (((*p-'0') & 02) > 0);
allow_exec = (((*p-'0') & 01) > 0);
break;
case 'p':
p_flag = TRUE;
break;
case 'q':
q_flag = TRUE;
break;
case 'u':
u_flag = TRUE;
break;
case 'v':
version(stdout);
exit(0);
default:
fprintf(stderr, "Unknown option\n");
exit(1);
}
argc--;
argv++;
}
str = cmdbuf;
*str = '\0';
while (--argc >= 0) {
i = (long)strlen(*argv);
if (str+1+i+2 >= cmdbuf+MAXCMD) {
fprintf(stderr, "command in arg list too long\n");
exit(1);
}
*str++ = ' ';
strcpy(str, *argv++);
str += i;
str[0] = '\n';
str[1] = '\0';
}
str = cmdbuf;
/*
* unbuffered mode
*/
if (u_flag) {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
}
/*
* initialize
*/
libcalc_call_me_first();
hash_init();
file_init();
initenv();
resetinput();
if (want_defhelp) {
givehelp(DEFAULTCALCHELP);
exit(0);
}
/*
* if allowed or needed, print version and setup bindings
*/
if (*str == '\0') {
/*
* check for pipe mode and/or non-tty stdin
*/
if (p_flag) {
stdin_tty = FALSE; /* stdin not a tty in pipe mode */
conf->tab_ok = FALSE; /* config("tab",0) if pipe mode */
} else {
stdin_tty = isatty(0); /* assume stdin is on fd 0 */
}
/*
* empty string arg is no string
*/
str = NULL;
/*
* if tty, setup bindings
*/
if (stdin_tty) {
version(stdout);
printf("[%s]\n\n",
"Type \"exit\" to exit, or \"help\" for help.");
}
if (stdin_tty) {
switch (hist_init(calcbindings)) {
case HIST_NOFILE:
fprintf(stderr,
"Cannot open bindings file \"%s\", %s.\n",
calcbindings, "fancy editing disabled");
break;
case HIST_NOTTY:
fprintf(stderr,
"Cannot set terminal modes, %s.\n",
"fancy editing disabled");
break;
}
}
} else {
/*
* process args, not stdin
*/
stdin_tty = FALSE; /* stdin not a tty in arg mode */
conf->tab_ok = FALSE; /* config("tab",0) if pipe mode */
}
/*
* establish error longjump point with initial conditions
*/
if (setjmp(jmpbuf) == 0) {
/*
* reset/initialize the computing environment
*/
post_init = TRUE; /* jmpbuf is ready for math_error() */
inittokens();
initglobals();
initfunctions();
initstack();
resetinput();
math_cleardiversions();
math_setfp(stdout);
math_setmode(MODE_INITIAL);
math_setdigits((long)DISPLAY_DEFAULT);
conf->maxprint = MAXPRINT_DEFAULT;
/*
* if arg mode or non-tty mode, just do the work and be gone
*/
if (str || !stdin_tty) {
if (q_flag == FALSE && allow_read) {
runrcfiles();
q_flag = TRUE;
}
if (str)
(void) openstring(str);
else
(void) openterminal();
start_done = TRUE;
getcommands(FALSE);
exit(0);
}
}
start_done = TRUE;
/*
* if in arg mode, we should not get here
*/
if (str)
exit(1);
/*
* process commands (from stdin, not the command line)
*/
abortlevel = 0;
_math_abort_ = FALSE;
inputwait = FALSE;
(void) signal(SIGINT, intint);
math_cleardiversions();
math_setfp(stdout);
resetscopes();
resetinput();
if (q_flag == FALSE && allow_read) {
q_flag = TRUE;
runrcfiles();
}
(void) openterminal();
getcommands(TRUE);
/*
* all done
*/
exit(0);
/*NOTREACHED*/
}
/*
* initenv - obtain $CALCPATH, $CALCRC, $CALCBINDINGS, $HOME, $PAGER
* and $SHELL values
*
* If $CALCPATH, $CALCRC, $CALCBINDINGS, $PAGER or $SHELL do not exist,
* use the default values. If $PAGER or $SHELL is an empty string, also
* use a default value. If $HOME does not exist, or is empty, use the home
* directory information from the password file.
*/
static void
initenv(void)
{
struct passwd *ent; /* our password entry */
/* determine the $CALCPATH value */
calcpath = getenv(CALCPATH);
if (calcpath == NULL)
calcpath = DEFAULTCALCPATH;
/* determine the $CALCRC value */
calcrc = getenv(CALCRC);
if (calcrc == NULL) {
calcrc = DEFAULTCALCRC;
}
/* determine the $CALCBINDINGS value */
calcbindings = getenv(CALCBINDINGS);
if (calcbindings == NULL) {
calcbindings = DEFAULTCALCBINDINGS;
}
/* determine the $HOME value */
home = getenv(HOME);
if (home == NULL || home[0] == '\0') {
ent = (struct passwd *)getpwuid(geteuid());
if (ent == NULL) {
/* just assume . is home if all else fails */
home = ".";
}
home = (char *)malloc(strlen(ent->pw_dir)+1);
strcpy(home, ent->pw_dir);
}
/* determine the $PAGER value */
pager = getenv(PAGER);
if (pager == NULL || *pager == '\0') {
pager = DEFAULTCALCPAGER;
}
/* determine the $SHELL value */
shell = getenv(SHELL);
if (shell == NULL)
shell = DEFAULTSHELL;
}
/*
* givehelp - display a help file
*
* given:
* type the type of help to give, NULL => index
*/
void
givehelp(char *type)
{
struct help_alias *p; /* help alias being considered */
char *helpcmd; /* what to execute to print help */
/*
* check permissions to see if we are allowed to help
*/
if (!allow_exec || !allow_read) {
fprintf(stderr,
"sorry, help is only allowed with -m mode 5 or 7\n");
return;
}
/* catch the case where we just print the index */
if (type == NULL) {
type = DEFAULTCALCHELP; /* the help index file */
}
/* alias the type of help, if needed */
for (p=halias; p->topic; ++p) {
if (strcmp(type, p->topic) == 0) {
type = p->filename;
break;
}
}
/* form the help command name */
helpcmd = (char *)malloc(
sizeof("if [ ! -d \"")+sizeof(HELPDIR)+1+strlen(type)+
sizeof("\" ];then ")+
strlen(pager)+1+1+sizeof(HELPDIR)+1+strlen(type)+1+1+
sizeof(";else echo no such help;fi"));
sprintf(helpcmd,
"if [ -r \"%s/%s\" ];then %s \"%s/%s\";else echo no such help;fi",
HELPDIR, type, pager, HELPDIR, type);
/* execute the help command */
system(helpcmd);
free(helpcmd);
}
/*
* Interrupt routine.
*
* given:
* arg to keep ANSI C happy
*/
/*ARGSUSED*/
static void
intint(int arg)
{
(void) signal(SIGINT, intint);
if (inputwait || (++abortlevel >= ABORT_NOW)) {
math_error("\nABORT");
/*NOTREACHED*/
}
if (abortlevel >= ABORT_MATH)
_math_abort_ = TRUE;
printf("\n[Abort level %d]\n", abortlevel);
}
/* END CODE */

165
calc.h Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Definitions for calculator program.
*/
#ifndef CALC_H
#define CALC_H
#include <stdio.h>
#include <setjmp.h>
#include "value.h"
/*
* Configuration definitions
*/
#define CALCPATH "CALCPATH" /* environment variable for files */
#define CALCRC "CALCRC" /* environment variable for startup */
#define CALCBINDINGS "CALCBINDINGS" /* environment variable for hist bindings */
#define HOME "HOME" /* environment variable for home dir */
#define PAGER "PAGER" /* environment variable for help */
#define SHELL "SHELL" /* environment variable for shell */
#define DEFAULTCALCHELP "help" /* help file that -h prints */
#define DEFAULTSHELL "sh" /* default shell to use */
#define CALCEXT ".cal" /* extension for files read in */
#define PATHSIZE 1024 /* maximum length of path name */
#define HOMECHAR '~' /* char which indicates home directory */
#define DOTCHAR '.' /* char which indicates current directory */
#define PATHCHAR '/' /* char which separates path components */
#define LISTCHAR ':' /* char which separates paths in a list */
#define MAXCMD 16384 /* maximum length of command invocation */
#define MAXERROR 512 /* maximum length of error message string */
#define SYMBOLSIZE 256 /* maximum symbol name size */
#define MAXINDICES 20 /* maximum number of indices for objects */
#define MAXLABELS 100 /* maximum number of user labels in function */
#define MAXOBJECTS 10 /* maximum number of object types */
#define MAXSTRING 1024 /* maximum size of string constant */
#define MAXSTACK 1000 /* maximum depth of evaluation stack */
#define MAXFILES 20 /* maximum number of opened files */
#define PROMPT1 "> " /* default normal prompt*/
#define PROMPT2 ">> " /* default prompt inside multi-line input */
#define TRACE_NORMAL 0x00 /* normal trace flags */
#define TRACE_OPCODES 0x01 /* trace every opcode */
#define TRACE_NODEBUG 0x02 /* suppress debugging opcodes */
#define TRACE_LINKS 0x04 /* display links for real and complex numbers */
#define TRACE_FNCODES 0x08 /* display code for newly defined function */
#define TRACE_MAX 0x0f /* maximum value for trace flag */
#define ABORT_NONE 0 /* abort not needed yet */
#define ABORT_STATEMENT 1 /* abort on statement boundary */
#define ABORT_OPCODE 2 /* abort on any opcode boundary */
#define ABORT_MATH 3 /* abort on any math operation */
#define ABORT_NOW 4 /* abort right away */
/*
* File ids corresponding to standard in, out, error, and when not in use.
*/
#define FILEID_STDIN ((FILEID) 0)
#define FILEID_STDOUT ((FILEID) 1)
#define FILEID_STDERR ((FILEID) 2)
#define FILEID_NONE ((FILEID) -1)
/*
* File I/O routines.
*/
extern FILEID openid(char *name, char *mode);
extern FILEID indexid(long index);
extern BOOL validid(FILEID id);
extern BOOL errorid(FILEID id);
extern BOOL eofid(FILEID id);
extern int closeid(FILEID id);
extern int getcharid(FILEID id);
extern int idprintf(FILEID id, char *fmt, int count, VALUE **vals);
extern int idfputc(FILEID id, int ch);
extern int idfputs(FILEID id, char *str);
extern int printid(FILEID id, int flags);
extern int flushid(FILEID id);
extern int readid(FILEID id, int flags, char **retptr);
extern int getloc(FILEID id, ZVALUE *loc);
extern int setloc(FILEID id, ZVALUE zpos);
extern int getsize(FILEID id, ZVALUE *size);
extern int get_device(FILEID id, ZVALUE *dev);
extern int get_inode(FILEID id, ZVALUE *ino);
extern FILEID reopenid(FILEID id, char *mode, char *name);
extern int closeall(void);
extern int flushall(void);
extern int idfputstr(FILEID id, char *str);
extern int rewindid(FILEID id);
extern void rewindall(void);
extern long filesize(FILEID id);
extern void showfiles(void);
extern int fscanfid(FILEID id, char *fmt, int count, VALUE **vals);
extern int scanfstr(char *str, char *fmt, int count, VALUE **vals);
extern long ftellid(FILEID id);
extern long fseekid(FILEID id, long offset, int whence);
extern int isattyid(FILEID id);
long fsearch(FILEID id, char *str, long pos);
long frsearch(FILEID id, char *str, long pos);
/*
* Input routines.
*/
extern FILE *f_open(char *name, char *mode);
extern int openstring(char *str);
extern int openterminal(void);
extern int opensearchfile(char *name, char *pathlist, char *exten, int reopen_ok);
extern char *nextline(void);
extern int nextchar(void);
extern void reread(void);
extern void resetinput(void);
extern void setprompt(char *);
extern BOOL inputisterminal(void);
extern char *inputname(void);
extern long linenumber(void);
extern void runrcfiles(void);
extern void closeinput(void);
extern FILE *curstream(void);
/*
* Other routines.
*/
extern NUMBER *constvalue(unsigned long index);
extern long addnumber(char *str);
extern long addqconstant(NUMBER *q);
extern void initstack(void);
extern void version(FILE *stream);
extern void getcommands(BOOL toplevel);
extern void givehelp(char *type);
extern void hash_init(void);
extern void libcalc_call_me_first(void);
/*
* Global data definitions.
*/
extern int abortlevel; /* current level of aborts */
extern BOOL inputwait; /* TRUE if in a terminal input wait */
extern VALUE *stack; /* execution stack */
extern jmp_buf jmpbuf; /* for errors */
extern int start_done; /* TRUE => start up processing finished */
extern int dumpnames; /* TRUE => dump names rather than indices */
extern char *calcpath; /* $CALCPATH or default */
extern char *calcrc; /* $CALCRC or default */
extern char *calcbindings; /* $CALCBINDINGS or default */
extern char *home; /* $HOME or default */
extern char *shell; /* $SHELL or default */
extern int allow_read; /* FALSE => may not open any files for reading */
extern int allow_write; /* FALSE => may not open any files for writing */
extern int allow_exec; /* FALSE => may not execute any commands */
extern int post_init; /* TRUE => setjmp for math_error is ready */
#endif
/* END CODE */

423
calc.man Normal file
View File

@@ -0,0 +1,423 @@
.\"
.\" Copyright (c) 1994 David I. Bell and Landon Curt Noll
.\" Permission is granted to use, distribute, or modify this source,
.\" provided that this copyright notice remains intact.
.\"
.\" calculator by David I. Bell
.\" man page by Landon Noll
.TH calc 1 "^..^" "15nov93"
.SH NAME
calc \- arbitrary precision calculator
.SH SYNOPSIS
\fIcalc\fP
[\fI\-h\fP]
[\fI\-m mode\fP]
[\fI\-p\fP]
[\fI\-q\fP]
[\fI\-u\fP]
[\fI\-v\fP]
[\fIcalc_cmd \&.\|.\|.\fp]
.SH DESCRIPTION
\&
.br
CALC COMMAND LINE
.PP
.TP
\fI\-h\fP
Print a help message.
This option implies \fI \-q\fP.
This is equivalent to the calc command \fIhelp help\fP.
The help facility is disabled unless the \fImode\fP is 5 or 7.
See \fI\-m\fP below.
.sp
.TP
\fI\-m mode\fP
This flag sets the permission mode of calc.
It controls the ability for \fIcalc\fP to open files
and execute programs.
\fIMode\fP may be a number from 0 to 7.
.sp
The \fImode\fP value is interpreted in a way similar
to that of the \fRchmod(1)\fP octal mode:
.sp
.in +0.5i
.nf
0 do not open any file, do not execute progs
1 do not open any file
2 do not open files for reading, do not execute progs
3 do not open files for reading
4 do not open files for writing, do not execute progs
5 do not open files for writing
6 do not execute any program
7 allow everything (default mode)
.fi
.in -0.5i
.sp
If one wished to run calc from a privledged user, one might
want to use \fI\-m 0\fP in an effort to make calc more secure.
.sp
\fIMode\fP bits for reading and writing apply only on an open.
Files already open are not effected.
Thus if one wanted to use the \fI\-m 0\fP in an effort to make
\fIcalc\fP more secure, but still wanted to read and write a specific
file, one might want to do:
.sp
.in +0.5i
.nf
\fRcalc \-m 0 3<a.file\fP
.fi
.in -0.5i
.sp
Files presented to \fIcalc\fP in this way are opened in an unknown mode.
\fICalc\fP will attempt to read or write them if directed.
.sp
If the \fImode\fP disables opening of files for reading, then
the startup library scripts are disabled as of \fI\-q\fP was given.
The reading of key bindings is also disabled when the \fImode\fP
disables opening of files for reading.
.TP
\fI \-p\fP
Pipe processing is enabled by use of \-p. For example:
.sp
.in +0.5i
.nf
\fRecho "print 2^21701\-1, 2^23209\-1" | calc \-p | fizzbin\fP
.fi
.in -0.5i
.sp
In pipe mode, \fIcalc\fP does not prompt, does not print leading tabs
and does not print the initial header.
.TP
\fI \-q\fP
Disable the use of the \fI$CALCRC\fP startup scripts.
.TP
\fI \-u\fP
Disable buffering of stdin and stdout.
.TP
\fI \-v\fP
Print the version and exit.
.PP
Without \fIcalc_cmd\fPs, \fIcalc\fP operates interactively.
If one or more \fIcalc_cmd\fPs are given on the command line,
\fIcalc\fP will execute them and exit.
The printing of leading tabs on output is disabled
as if \fIconfig("tab",0)\fP had been executed.
.PP
Normally on startup, \fIcalc\fP attempts to execute a collection
of library scripts.
The environment variable \fI$CALCRC\fP (if non-existent then
a compiled in value) contains a \fI:\fP separated list of
startup library scripts.
No error conditions are produced if these startup library scripts
are not found.
.PP
If the \fImode\fP disables opening of files for reading, then
the startup library scripts are disabled as of \fI\-q\fP was given
and \fI$CALCRC\fP as well as the default compiled in value are ignored.
.PP
Filenames are subject to ``~'' expansion (see below).
The environment variable \fI$CALCPATH\fP (if non-existent then
a compiled in value) contains a \fI:\fP separated list of search
directories.
If a file does not begin with \fI/\fP, \fI~\fP or \fI./\fP,
then it is searched for under each directory listed in the \fI$CALCPATH\fP.
It is an error if no such readable file is found.
.PP
Calc treats all open files, other than stdin, stdout and stderr
as files available for reading and writing.
One may present calc with an already open file in the following way:
.sp
.in +0.5i
.nf
\fRcalc 3<open_file 4<open_file2\fP
.fi
.in -0.5i
.PP
For more information use the following calc commands:
.PP
.in 1.0i
help usage
.br
help help
.br
help environment
.in -1.0i
.PP
OVERVIEW
.PP
\fICalc\fP is arbitrary precision arithmetic system that uses
a C-like language.
\fICalc\fP is useful as a calculator, an algorithm prototyped
and as a mathematical research tool.
More importantly, \fIcalc\fP provides one with a machine
independent means of computation.
.PP
\fICalc\fP comes with a rich set of builtin mathematical
and programmatic functions.
.PP
\fICalc\fP is distributed with library of scripts.
Written in the same C-like language, library scripts may be
read in and executed during a \fIcalc\fP session.
These library scripts are also provided because they are
useful and to serve as examples of the \fIcalc\fP language.
One may further extend \fIcalc\fP thru the
use of user defined scripts.
.PP
Internally calc represents numeric values as fractions reduced to their
lowest terms.
The numerators and denominators of these factions may grow to
arbitrarily large values.
Numeric values read in are automatically converted into rationals.
The user need not be aware of this internal representation.
.PP
For more information use the following calc commands:
.PP
.in 1.0i
help intro
.br
help builtin
.br
help stdlib
.br
help define
.br
show builtins
.br
show functions
.in -1.0i
.PP
DATA TYPES
.PP
Fundamental builtin data types include integers, real numbers,
rational numbers, complex numbers and strings.
.PP
By use of an object, one may define an arbitrarily complex
data types.
One may define how such objects behave a wide range of
operations such as addition, subtraction,
multiplication, division, negation, squaring, modulus,
rounding, exponentiation, equality, comparison, printing
and so on.
.PP
For more information use the following calc commands:
.PP
.in 1.0i
help types
.br
help obj
.br
show objfuncs
.in -1.0i
.PP
VARIABLES
.PP
Variables in \fIcalc\fP are typeless.
In other words, the fundamental type of a variable is determined by its content.
Before a variable is assigned a value it has the value of zero.
.PP
The scope of a variable may be global, local to a file, or local to a
procedure.
Values may be grouped together in a matrix, or into a
a list that permits stack and queue style operations.
.PP
For more information use the following calc commands:
.PP
.in 1.0i
help variable
.br
help mat
.br
help list
.br
show globals
.in -1.0i
.PP
INPUT/OUTPUT
.PP
A leading ``0x'' implies a hexadecimal value,
a leading ``0b'' implies a binary value,
and a ``0'' followed by a digit implies an octal value.
Complex numbers are indicated by a trailing ``i'' such as in ``3+4i''.
Strings may be delimited by either a pair of single or double quotes.
By default, \fIcalc\fP prints values as if they were floating point numbers.
One may change the default to print values in a number of modes
including fractions, integers and exponentials.
.PP
A number of stdio-like file I/O operations are provided.
One may open, read, write, seek and close files.
Filenames are subject to ``\~'' expansion to home directories
in a way similar to that of the Korn or C-Shell.
.PP
For example:
.PP
.in 1.0i
~/.calcrc
.br
~chongo/lib/fft_multiply.cal
.in -1.0i
.PP
For more information use the following calc command:
.PP
.in 1.0i
help file
.in -1.0i
.PP
CALC LANGUAGE
.PP
The \fIcalc\fP language is a C-like language.
The language includes commands such as variable declarations,
expressions, tests, labels, loops, file operations, function calls.
These commands are very similar to their counterparts in C.
.PP
The language also include a number of commands particular
to \fIcalc\fP itself.
These include commands such as function definition, help,
reading in library scripts, dump files to a file, error notification,
configuration control and status.
.PP
For more information use the following calc command:
.PP
.in 1.0i
help command
.br
help statement
.br
help expression
.br
help operator
.br
help config
.in -1.0i
.PP
.SH FILES
\&
.br
.PD 0
.TP 20
${LIBDIR}/*.cal
library scripts shipped with calc
.br
.sp
.TP 20
${LIBDIR}/help/*
help files
.br
.sp
.TP 20
${LIBDIR}/bindings
command line editor bindings
.sp
.SH ENVIRONMENT
\&
.br
.PD 0
.TP 5
CALCPATH
A :-separated list of directories used to search for
scripts filenames that do not begin with /, ./ or ~.
.br
.sp
Default value: .:./lib:~/lib:${LIBDIR}
.br
.sp
.TP 5
CALCRC
On startup (unless \-h or \-q was given on the command
line), calc searches for files along this :-separated
environment variable.
.br
.sp
Default value: ${LIBDIR}/startup:~/.calcrc
.br
.sp
.TP 5
CALCBINDINGS
On startup (unless \fI\-h\fP or \fI\-q\fP was given on the command
line, or \fI\-m\fP disallows opening files for reading), calc reads
key bindings from the filename specified
by this environment variable.
.br
.sp
Default value: ${LIBDIR}/bindings
.sp
.SH CREDIT
\&
.br
The majority of calc was written by David I. Bell.
.sp
Calc archives and calc-tester mailing list maintained by Landon Curt Noll.
.sp
Thanks for suggestions and encouragement from Peter Miller,
Neil Justusson, and Landon Noll.
.sp
Thanks to Stephen Rothwell for writing the original version of
hist.c which is used to do the command line editing.
.sp
Thanks to Ernest W. Bowen for supplying many improvements in
accuracy and generality for some numeric functions. Much of
this was in terms of actual code which I gratefully accepted.
Ernest also supplied the original text for many of the help files.
.sp
Portions of this program are derived from an earlier set of
public domain arbitrarily precision routines which was posted
to the net around 1984. By now, there is almost no recognizable
code left from that original source.
.sp
Most of this source and binary has one of the following copyrights:
.sp
.in +0.5i
Copyright (c) 19xx David I. Bell
.br
Copyright (c) 19xx David I. Bell and Landon Curt Noll
.br
Copyright (c) 19xx Landon Curt Noll
.br
Copyright (c) 19xx Ernest Bowen and Landon Curt Noll
.in -0.5i
.sp
Permission is granted to use, distribute, or modify this source,
provided that this copyright notice remains intact.
.sp
Send calc comments, suggestions, bug fixes, enhancements
and interesting calc scripts that you would like you see included
in future distributions to:
.sp
.in +0.5i
dbell@auug.org.au
.br
chongo@toad.com
.in -0.5i
.sp
Landon Noll maintains the official calc ftp archive at:
.sp
.in +0.5i
ftp://ftp.uu.net/pub/calc
.in -0.5i
.sp
Alpha test versions, complete with bugs, untested code and
experimental features may be fetched (if you are brave) under:
.sp
.in +0.5i
http://reality.sgi.com/chongo/calc/
.in -0.5i
.sp
One may join the calc testing group by sending a request to:
.sp
.in +0.5i
calc-tester-request@postofc.corp.sgi.com
.in -0.5i
.sp
Your message body (not the subject) should consist of:
.sp
.in +0.5i
subscribe calc-tester address
.br
end
.br
name your_full_name
.sp
where "address" is your EMail address and "your_full_name"
is your full name.
.in -0.5i
.sp
Enjoy!

193
calcerr.tbl Normal file
View File

@@ -0,0 +1,193 @@
# This file is used to build calcerr.h include file.
#
# Lines should be of the form:
#
# SYMBOL meaning
E_1OVER0 Division by zero
E_0OVER0 Indeterminate (0/0)
E_ADD Bad arguments for +
E_SUB Bad arguments for binary -
E_MUL Bad arguments for *
E_DIV Bad arguments for /
E_NEG Bad argument for unary -
E_SQUARE Bad argument for squaring
E_INV Bad argument for inverse
E_INCV Bad argument for ++
E_DECV Bad argument for --
E_INT Bad argument for int
E_FRAC Bad argument for frac
E_CONJ Bad argument for conj
E_APPR Bad first argument for appr
E_APPR2 Bad second argument for appr
E_APPR3 Bad third argument for appr
E_ROUND Bad first argument for round
E_ROUND2 Bad second argument for round
E_ROUND3 Bad third argument for round
E_BROUND Bad first argument for bround
E_BROUND2 Bad second argument for bround
E_BROUND3 Bad third argument for bround
E_SQRT Bad first argument for sqrt
E_SQRT2 Bad second argument for sqrt
E_SQRT3 Bad third argument for sqrt
E_ROOT Bad first argument for root
E_ROOT2 Bad second argument for root
E_ROOT3 Bad third argument for root
E_NORM Bad argument for norm
E_SHIFT Bad first argument for << or >>
E_SHIFT2 Bad second argument for << or >>
E_SCALE Bad first argument for scale
E_SCALE2 Bad second argument for scale
E_POWI Bad first argument for ^
E_POWI2 Bad second argument for ^
E_POWER Bad first argument for power
E_POWER2 Bad second argument for power
E_POWER3 Bad third argument for power
E_QUO Bad first argument for quo or //
E_QUO2 Bad second argument for quo or //
E_QUO3 Bad third argument for quo
E_MOD Bad first argument for mod or %
E_MOD2 Bad second argument for mod or %
E_MOD3 Bad third argument for mod
E_SGN Bad argument for sgn
E_ABS Bad first argument for abs
E_ABS2 Bad second argument for abs
E_EVAL Scan error in argument for eval
E_STR Non-simple type for str
E_EXP1 Non-real epsilon for exp
E_EXP2 Bad first argument for exp
E_FPUTC1 Non-file first argument for fputc
E_FPUTC2 Bad second argument for fputc
E_FPUTC3 File not open for writing for fputc
E_FGETC1 Non-file first argument for fgetc
E_FGETC2 File not open for reading for fgetc
E_FOPEN1 Non-string arguments for fopen
E_FOPEN2 Unrecognized mode for fopen
E_FREOPEN1 Non-file first argument for freopen
E_FREOPEN2 Non-string or unrecognized mode for freopen
E_FREOPEN3 Non-string third argument for freopen
E_FCLOSE1 Non-file argument for fclose
E_FFLUSH Non-file argument for fflush
E_FPUTS1 Non-file first argument for fputs
E_FPUTS2 Non-string argument after first for fputs
E_FPUTS3 File not open for writing for fputs
E_FGETS1 Non-file argument for fgets
E_FGETS2 File not open for reading for fgets
E_FPUTSTR1 Non-file first argument for fputstr
E_FPUTSTR2 Non-string argument after first for fputstr
E_FPUTSTR3 File not open for writing for fputstr
E_FGETSTR1 Non-file first argument for fgetstr
E_FGETSTR2 File not open for reading for fgetstr
E_FGETLINE1 Non-file argument for fgetline
E_FGETLINE2 File not open for reading for fgetline
E_FGETWORD1 Non-file argument for fgetword
E_FGETWORD2 File not open for reading for fgetword
E_REWIND1 Non-file argument for rewind
E_FILES Non-integer argument for files
E_PRINTF1 Non-string fmt argument for fprint
E_PRINTF2 Stdout not open for writing to ???
E_FPRINTF1 Non-file first argument for fprintf
E_FPRINTF2 Non-string second (fmt) argument for fprintf
E_FPRINTF3 File not open for writing for fprintf
E_STRPRINTF1 Non-string first (fmt) argument for strprintf
E_STRPRINTF2 Error in attempting strprintf ???
E_FSCAN1 Non-file first argument for fscan
E_FSCAN2 File not open for reading for fscan
E_STRSCAN Non-string first argument for strscan
E_FSCANF1 Non-file first argument for fscanf
E_FSCANF2 Non-string second (fmt) argument for fscanf
E_FSCANF3 Non-lvalue argument after second for fscanf
E_FSCANF4 File not open for reading or other error for fscanf
E_STRSCANF1 Non-string first argument for strscanf
E_STRSCANF2 Non-string second (fmt) argument for strscanf
E_STRSCANF3 Non-lvalue argument after second for strscanf
E_STRSCANF4 Some error in attempting strscanf ???
E_SCANF1 Non-string first (fmt) argument for scanf
E_SCANF2 Non-lvalue argument after first for scanf
E_SCANF3 Some error in attempting scanf ???
E_FTELL1 Non-file argument for ftell
E_FTELL2 File not open or other error for ftell
E_FSEEK1 Non-file first argument for fseek
E_FSEEK2 Non-integer or negative second argument for fseek
E_FSEEK3 File not open or other error for fseek
E_FSIZE1 Non-file argument for fsize
E_FSIZE2 File not open or other error for fsize
E_FEOF1 Non-file argument for feof
E_FEOF2 File not open or other error for feof
E_FERROR1 Non-file argument for ferror
E_FERROR2 File not open or other error for ferror
E_UNGETC1 Non-file argument for ungetc
E_UNGETC2 File not open for reading for ungetc
E_UNGETC3 Bad second argument or other error for ungetc
E_BIGEXP Exponent too big in scanning
E_ISATTY1 Non-file argument for isatty
E_ISATTY2 File not open for isatty
E_ACCESS1 Non-string first argument for access
E_ACCESS2 Bad second argument for access
E_SEARCH1 Bad first argument for search
E_SEARCH2 Bad second argument for search
E_SEARCH3 Bad third argument for search
E_RSEARCH1 Bad first argument for rsearch
E_RSEARCH2 Bad second argument for rsearch
E_RSEARCH3 Bad third argument for rsearch
E_FOPEN3 Too many open files
E_REWIND2 Attempt to rewind a file that is not open
E_STRERROR1 Bad argument type for strerror
E_STRERROR2 Index out of range for strerror
E_COS1 Bad epsilon for cos
E_COS2 Bad first argument for cos
E_SIN1 Bad epsilon for sin
E_SIN2 Bad first argument for sin
E_EVAL2 Non-string argument for eval
E_ARG1 Bad epsilon for arg
E_ARG2 Bad first argument for arg
E_POLAR1 Non-real argument for polar
E_POLAR2 Bad epsilon for polar
E_FCNT Non-integral argument for fcnt
E_MATFILL1 Non-variable first argument for matfill
E_MATFILL2 Non-matrix first argument-value for matfill
E_MATDIM Non-matrix argument for matdim
E_MATSUM Non-matrix argument for matsum
E_ISIDENT Non-matrix argument for isident
E_MATTRANS1 Non-matrix argument for mattrans
E_MATTRANS2 Non-two-dimensional matrix for mattrans
E_DET1 Non-matrix argument for det
E_DET2 Matrix for det not of dimension 2
E_DET3 Non-square matrix for det
E_MATMIN1 Non-matrix first argument for matmin
E_MATMIN2 Non-positive-integer second argument for matmin
E_MATMIN3 Second argument for matmin exceeds dimension
E_MATMAX1 Non-matrix first argument for matmin
E_MATMAX2 Second argument for matmax not positive integer
E_MATMAX3 Second argument for matmax exceeds dimension
E_CP1 Non-matrix argument for cp
E_CP2 Non-one-dimensional matrix for cp
E_CP3 Matrix size not 3 for cp
E_DP1 Non-matrix argument for dp
E_DP2 Non-one-dimensional matrix for dp
E_DP3 Different-size matrices for dp
E_STRLEN Non-string argument for strlen
E_STRCAT Non-string argument for strcat
E_SUBSTR1 Non-string first argument for strcat
E_SUBSTR2 Non-non-negative integer second argument for strcat
E_CHAR Bad argument for char
E_ORD Non-string argument for ord
E_INSERT1 Non-list-variable first argument for insert
E_INSERT2 Non-integral second argument for insert
E_PUSH Non-list-variable first argument for push
E_APPEND Non-list-variable first argument for append
E_DELETE1 Non-list-variable first argument for delete
E_DELETE2 Non-integral second argument for delete
E_POP Non-list-variable argument for pop
E_REMOVE Non-list-variable argument for remove
E_LN1 Bad epsilon argument for ln
E_LN2 Non-numeric first argument for ln
E_ERROR1 Non-integer argument for error
E_ERROR2 Argument outside range for error
E_EVAL3 Attempt to eval at maximum input depth
E_EVAL4 Unable to open string for reading
E_RM1 First argument for rm is not a non-empty string
E_RM2 Unable to remove a file
E_RDPERM Operation allowed because calc mode disallows read operations
E_WRPERM Operation allowed because calc mode disallows write operations
E_EXPERM Operation allowed because calc mode disallows exec operations

17
calcerr_c.awk Normal file
View File

@@ -0,0 +1,17 @@
BEGIN {
printf("#include <stdio.h>\n");
printf("#include \"calcerr.h\"\n\n");
printf("#include \"have_const.h\"\n\n");
printf("/*\n");
printf(" * names of calc error values\n");
printf(" */\n");
printf("CONST char *error_table[E__COUNT+2] = {\n");
printf(" \"No error\",\n");
}
{
print $0;
}
END {
printf(" NULL\n");
printf("};\n");
}

4
calcerr_c.sed Normal file
View File

@@ -0,0 +1,4 @@
s/#.*//
s/[ ][ ]*$//
/^$/d
s/[^ ][^ ]*[ ][ ]*\(.*\)$/ "\1",/

22
calcerr_h.awk Normal file
View File

@@ -0,0 +1,22 @@
BEGIN {
ebase = 10000;
printf("#define E__BASE %d\t/* calc errors start above here */\n\n", ebase);
}
NF > 1 {
if (length($1) > 7) {
printf("#define %s\t", $1, NR);
} else {
printf("#define %s\t\t", $1, NR);
}
printf("%d\t/* ", ebase+NR);
for (i=2; i < NF; ++i) {
printf("%s ", $i);
}
printf("%s */\n", $NF);
}
END {
printf("\n#define E__HIGHEST\t%d\t/* highest calc error */\n", NR+ebase);
printf("#define E__COUNT\t\t%d\t/* number of calc errors */\n", NR);
printf("#define E_USERDEF\t20000\t/* base of user defined errors */\n\n");
printf("/* names of calc error values */\n");
}

4
calcerr_h.sed Normal file
View File

@@ -0,0 +1,4 @@
s/#.*//
s/[ ][ ]*$//
/^$/d
s/\([^ ][^ ]*\)[ ][ ]*\(.*\)$/\1 \2/

74
check.awk Normal file
View File

@@ -0,0 +1,74 @@
# This awk script will print 3 lines before and after any non-blank line that
# does not begin with a number. This allows the 'make debug' rule to remove
# all non-interest lines the the 'make check' regression output while providing
# 3 lines of context around unexpected output.
#
BEGIN {
havebuf0=0;
buf0=0;
havebuf1=0;
buf1=0;
havebuf2=0;
buf2=0;
error = 0;
}
NF == 0 {
if (error > 0) {
if (havebuf2) {
print buf2;
}
--error;
}
buf2 = buf1;
havebuf2 = havebuf1;
buf1 = buf0;
havebuf1 = havebuf0;
buf0 = $0;
havebuf0 = 1;
next;
}
$1 ~ /^[0-9]/ {
if (error > 0) {
if (havebuf2) {
print buf2;
}
--error;
}
buf2 = buf1;
havebuf2 = havebuf1;
buf1 = buf0;
havebuf1 = havebuf0;
buf0 = $0;
havebuf0 = 1;
next;
}
{
error = 6;
if (havebuf2) {
print buf2;
}
buf2 = buf1;
havebuf2 = havebuf1;
buf1 = buf0;
havebuf1 = havebuf0;
buf0 = $0;
havebuf0 = 1;
next;
}
END {
if (error > 0 && havebuf2) {
print buf2;
--error;
}
if (error > 0 && havebuf1) {
print buf1;
--error;
}
if (error > 0 && havebuf0) {
print buf0;
}
}

113
cmath.h Normal file
View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Data structure declarations for extended precision complex arithmetic.
*/
#ifndef CMATH_H
#define CMATH_H
#include "qmath.h"
/*
* Complex arithmetic definitions.
*/
typedef struct {
NUMBER *real; /* real part of number */
NUMBER *imag; /* imaginary part of number */
long links; /* link count */
} COMPLEX;
/*
* Input, output, and conversion routines.
*/
extern COMPLEX *comalloc(void);
extern COMPLEX *qqtoc(NUMBER *q1, NUMBER *q2);
extern void comfree(COMPLEX *c);
extern void comprint(COMPLEX *c);
extern void cprintfr(COMPLEX *c);
/*
* Basic numeric routines.
*/
extern COMPLEX *cadd(COMPLEX *c1, COMPLEX *c2);
extern COMPLEX *csub(COMPLEX *c1, COMPLEX *c2);
extern COMPLEX *cmul(COMPLEX *c1, COMPLEX *c2);
extern COMPLEX *cdiv(COMPLEX *c1, COMPLEX *c2);
extern COMPLEX *caddq(COMPLEX *c, NUMBER *q);
extern COMPLEX *csubq(COMPLEX *c, NUMBER *q);
extern COMPLEX *cmulq(COMPLEX *c, NUMBER *q);
extern COMPLEX *cdivq(COMPLEX *c, NUMBER *q);
extern COMPLEX *cscale(COMPLEX *c, long i);
extern COMPLEX *cshift(COMPLEX *c, long i);
extern COMPLEX *csquare(COMPLEX *c);
extern COMPLEX *cconj(COMPLEX *c);
extern COMPLEX *creal(COMPLEX *c);
extern COMPLEX *cimag(COMPLEX *c);
extern COMPLEX *cneg(COMPLEX *c);
extern COMPLEX *cinv(COMPLEX *c);
extern COMPLEX *cint(COMPLEX *c);
extern COMPLEX *cfrac(COMPLEX *c);
extern BOOL ccmp(COMPLEX *c1, COMPLEX *c2);
/*
* More complicated functions.
*/
extern COMPLEX *cpowi(COMPLEX *c, NUMBER *q);
/*
* Transcendental routines. These all take an epsilon argument to
* specify how accurately these are to be calculated.
*/
extern COMPLEX *cpower(COMPLEX *c1, COMPLEX *c2, NUMBER *epsilon);
extern COMPLEX *csqrt(COMPLEX *c, NUMBER *epsilon, long R);
extern COMPLEX *croot(COMPLEX *c, NUMBER *q, NUMBER *epsilon);
extern COMPLEX *cexp(COMPLEX *c, NUMBER *epsilon);
extern COMPLEX *cln(COMPLEX *c, NUMBER *epsilon);
extern COMPLEX *ccos(COMPLEX *c, NUMBER *epsilon);
extern COMPLEX *csin(COMPLEX *c, NUMBER *epsilon);
extern COMPLEX *cpolar(NUMBER *q1, NUMBER *q2, NUMBER *epsilon);
extern COMPLEX *crel(COMPLEX *c1, COMPLEX *c2);
/*
* external functions
*/
extern COMPLEX *swap_b8_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all);
extern COMPLEX *swap_b16_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all);
extern COMPLEX *swap_HALF_in_COMPLEX(COMPLEX *dest, COMPLEX *src, BOOL all);
/*
* macro expansions to speed this thing up
*/
#define cisreal(c) (qiszero((c)->imag))
#define cisimag(c) (qiszero((c)->real) && !cisreal(c))
#define ciszero(c) (cisreal(c) && qiszero((c)->real))
#define cisone(c) (cisreal(c) && qisone((c)->real))
#define cisnegone(c) (cisreal(c) && qisnegone((c)->real))
#define cisrunit(c) (cisreal(c) && qisunit((c)->real))
#define cisiunit(c) (qiszero((c)->real) && qisunit((c)->imag))
#define cisunit(c) (cisrunit(c) || cisiunit(c))
#define cistwo(c) (cisreal(c) && qistwo((c)->real))
#define cisint(c) (qisint((c)->real) && qisint((c)->imag))
#define ciseven(c) (qiseven((c)->real) && qiseven((c)->imag))
#define cisodd(c) (qisodd((c)->real) || qisodd((c)->imag))
#define clink(c) ((c)->links++, (c))
/*
* Pre-defined values.
*/
extern COMPLEX _czero_, _cone_, _conei_;
#endif
/* END CODE */

2115
codegen.c Normal file

File diff suppressed because it is too large Load Diff

770
comfunc.c Normal file
View File

@@ -0,0 +1,770 @@
/*
* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Extended precision complex arithmetic non-primitive routines
*/
#include "config.h"
#include "cmath.h"
/*
* Compute the result of raising a complex number to an integer power.
*
* given:
* c complex number to be raised
* q power to raise it to
*/
COMPLEX *
cpowi(COMPLEX *c, NUMBER *q)
{
COMPLEX *tmp, *res; /* temporary values */
long power; /* power to raise to */
FULL bit; /* current bit value */
int sign;
if (qisfrac(q)) {
math_error("Raising number to non-integral power");
/*NOTREACHED*/
}
if (zge31b(q->num)) {
math_error("Raising number to very large power");
/*NOTREACHED*/
}
power = ztolong(q->num);
if (ciszero(c) && (power == 0)) {
math_error("Raising zero to zeroth power");
/*NOTREACHED*/
}
sign = 1;
if (qisneg(q))
sign = -1;
/*
* Handle some low powers specially
*/
if (power <= 4) {
switch ((int) (power * sign)) {
case 0:
return clink(&_cone_);
case 1:
return clink(c);
case -1:
return cinv(c);
case 2:
return csquare(c);
case -2:
tmp = csquare(c);
res = cinv(tmp);
comfree(tmp);
return res;
case 3:
tmp = csquare(c);
res = cmul(c, tmp);
comfree(tmp);
return res;
case 4:
tmp = csquare(c);
res = csquare(tmp);
comfree(tmp);
return res;
}
}
/*
* Compute the power by squaring and multiplying.
* This uses the left to right method of power raising.
*/
bit = TOPFULL;
while ((bit & power) == 0)
bit >>= 1L;
bit >>= 1L;
res = csquare(c);
if (bit & power) {
tmp = cmul(res, c);
comfree(res);
res = tmp;
}
bit >>= 1L;
while (bit) {
tmp = csquare(res);
comfree(res);
res = tmp;
if (bit & power) {
tmp = cmul(res, c);
comfree(res);
res = tmp;
}
bit >>= 1L;
}
if (sign < 0) {
tmp = cinv(res);
comfree(res);
res = tmp;
}
return res;
}
/*
* Calculate the square root of a complex number to specified accuracy.
* Type of rounding of each component specified by R as for qsqrt().
*/
COMPLEX *
csqrt(COMPLEX *c, NUMBER *epsilon, long R)
{
COMPLEX *r;
NUMBER *es, *aes, *bes, *u, *v, qtemp;
NUMBER *ntmp;
ZVALUE g, a, b, d, aa, cc;
ZVALUE tmp1, tmp2, tmp3, mul1, mul2;
long s1, s2, s3, up1, up2;
int imsign, sign;
if (ciszero(c))
return clink(c);
if (cisreal(c)) {
r = comalloc();
if (!qisneg(c->real)) {
r->real = qsqrt(c->real, epsilon, R);
return r;
}
ntmp = qneg(c->real);
r->imag = qsqrt(ntmp, epsilon, R);
qfree(ntmp);
return r;
}
up1 = up2 = 0;
sign = (R & 64) != 0;
#if 0
if (qiszero(epsilon)) {
aes = qsquare(c->real);
bes = qsquare(c->imag);
v = qqadd(aes, bes);
qfree(aes);
qfree(bes);
u = qsqrt(v, epsilon, 0);
qfree(v);
if (qiszero(u)) {
qfree(u);
return clink(&_czero_);
}
aes = qqadd(u, c->real);
qfree(u);
bes = qscale(aes, -1);
qfree(aes);
u = qsqrt(bes, epsilon, R);
qfree(bes);
if (qiszero(u)) {
qfree(u);
return clink(&_czero_);
}
aes = qscale(c->imag, -1);
v = qdiv(aes, u);
qfree(aes);
r = comalloc();
r->real = u;
r->imag = v;
return r;
}
#endif
imsign = c->imag->num.sign;
es = qsquare(epsilon);
aes = qdiv(c->real, es);
bes = qdiv(c->imag, es);
qfree(es);
zgcd(aes->den, bes->den, &g);
zequo(bes->den, g, &tmp1);
zmul(aes->num, tmp1, &a);
zmul(aes->den, tmp1, &tmp2);
zshift(tmp2, 1, &d);
zfree(tmp1);
zfree(tmp2);
zequo(aes->den, g, &tmp1);
zmul(bes->num, tmp1, &b);
zfree(tmp1);
zfree(g);
qfree(aes);
qfree(bes);
zsquare(a, &tmp1);
zsquare(b, &tmp2);
zfree(b);
zadd(tmp1, tmp2, &tmp3);
zfree(tmp1);
zfree(tmp2);
if (R & 16) {
zshift(tmp3, 4, &tmp1);
zfree(tmp3);
zshift(a, 2, &aa);
zfree(a);
s1 = zsqrt(tmp1, &cc, 16);
zfree(tmp1);
zadd(cc, aa, &tmp1);
if (s1 == 0 && R & 32) {
zmul(tmp1, d, &tmp2);
zfree(tmp1);
s2 = zsqrt(tmp2, &tmp3, 16);
zfree(tmp2);
if (s2 == 0) {
aes = qalloc();
zshift(d, 1, &tmp1);
zreduce(tmp3, tmp1, &aes->num, &aes->den);
zfree(tmp1);
zfree(tmp3);
zfree(aa);
zfree(cc);
zfree(d);
r = comalloc();
qtemp = *aes;
qtemp.num.sign = sign;
r->real = qmul(&qtemp, epsilon);
qfree(aes);
bes = qscale(r->real, 1);
qtemp = *bes;
qtemp.num.sign = sign ^ imsign;
r->imag = qdiv(c->imag, &qtemp);
qfree(bes);
return r;
}
s3 = zquo(tmp3, d, &tmp1, s2 < 0);
}
else {
s2 = zquo(tmp1, d, &tmp3, s1 ? (s1 < 0) : 16);
zfree(tmp1);
s3 = zsqrt(tmp3,&tmp1,(s1||s2) ? (s1<0 || s2<0) : 16);
}
zfree(tmp3);
zshift(tmp1, -1, &mul1);
if (*tmp1.v & 1)
up1 = s1 + s2 + s3;
else
up1 = -1;
zfree(tmp1);
zsub(cc, aa, &tmp1);
s2 = zquo(tmp1, d, &tmp2, s1 ? (s1 < 0) : 16);
zfree(tmp1);
s3 = zsqrt(tmp2, &tmp1, (s1 || s2) ? (s1 < 0 || s2 < 0) : 16);
zfree(tmp2);
zshift(tmp1, -1, &mul2);
if (*tmp1.v & 1)
up2 = s1 + s2 + s3;
else
up2 = -1;
zfree(tmp1);
zfree(aa);
}
else {
s1 = zsqrt(tmp3, &cc, 0);
zfree(tmp3);
zadd(cc, a, &tmp1);
if (s1 == 0 && R & 32) {
zmul(tmp1, d, &tmp2);
zfree(tmp1);
s2 = zsqrt(tmp2, &tmp3, 0);
zfree(tmp2);
if (s2 == 0) {
aes = qalloc();
zreduce(tmp3, d, &aes->num, &aes->den);
zfree(tmp3);
zfree(a);
zfree(cc);
zfree(d);
r = comalloc();
qtemp = *aes;
qtemp.num.sign = sign;
r->real = qmul(&qtemp, epsilon);
qfree(aes);
bes = qscale(r->real, 1);
qtemp = *bes;
qtemp.num.sign = sign ^ imsign;
r->imag = qdiv(c->imag, &qtemp);
qfree(bes);
return r;
}
s3 = zquo(tmp3, d, &mul1, 0);
}
else {
s2 = zquo(tmp1, d, &tmp3, 0);
zfree(tmp1);
s3 = zsqrt(tmp3, &mul1, 0);
}
up1 = (s1 + s2 + s3) ? 0 : -1;
zfree(tmp3);
zsub(cc, a, &tmp1);
s2 = zquo(tmp1, d, &tmp2, 0);
zfree(tmp1);
s3 = zsqrt(tmp2, &mul2, 0);
up2 = (s1 + s2 + s3) ? 0 : -1;
zfree(tmp2);
zfree(a);
}
zfree(cc); zfree(d);
if (up1 == 0) {
if (R & 8)
up1 = (long)((R ^ *mul1.v) & 1);
else
up1 = (R ^ epsilon->num.sign ^ sign) & 1;
if (R & 2)
up1 ^= epsilon->num.sign ^ sign;
if (R & 4)
up1 ^= epsilon->num.sign;
}
if (up2 == 0) {
if (R & 8)
up2 = (long)((R ^ *mul2.v) & 1);
else
up2 = (R ^ epsilon->num.sign ^ sign ^ imsign) & 1;
if (R & 2)
up2 ^= epsilon->num.sign ^ imsign ^ sign;
if (R & 4)
up2 ^= epsilon->num.sign;
}
if (up1 > 0) {
zadd(mul1, _one_, &tmp1);
zfree(mul1);
mul1 = tmp1;
}
if (up2 > 0) {
zadd(mul2, _one_, &tmp2);
zfree(mul2);
mul2 = tmp2;
}
if (ziszero(mul1))
u = qlink(&_qzero_);
else {
mul1.sign = sign ^ epsilon->num.sign;
u = qalloc();
zreduce(mul1, epsilon->den, &tmp2, &u->den);
zmul(tmp2, epsilon->num, &u->num);
zfree(tmp2);
}
zfree(mul1);
if (ziszero(mul2))
v = qlink(&_qzero_);
else {
mul2.sign = imsign ^ sign ^ epsilon->num.sign;
v = qalloc();
zreduce(mul2, epsilon->den, &tmp2, &v->den);
zmul(tmp2, epsilon->num, &v->num);
zfree(tmp2);
}
zfree(mul2);
if (qiszero(u) && qiszero(v)) {
qfree(u);
qfree(v);
return clink(&_czero_);
}
r = comalloc();
if (!qiszero(u))
r->real = u;
if (!qiszero(v))
r->imag = v;
return r;
}
/*
* Take the Nth root of a complex number, where N is a positive integer.
* Each component of the result is within the specified error.
*/
COMPLEX *
croot(COMPLEX *c, NUMBER *q, NUMBER *epsilon)
{
COMPLEX *r;
NUMBER *a2pb2, *root, *tmp1, *tmp2, *epsilon2;
long n, m;
if (qisneg(q) || qiszero(q) || qisfrac(q)) {
math_error("Taking bad root of complex number");
/*NOTREACHED*/
}
if (cisone(c) || qisone(q))
return clink(c);
if (qistwo(q))
return csqrt(c, epsilon, 24L);
if (cisreal(c) && !qisneg(c->real)) {
r = comalloc();
r->real = qroot(c->real, q, epsilon);
return r;
}
/*
* Calculate the root using the formula:
* croot(a + bi, n) =
* cpolar(qroot(a^2 + b^2, 2 * n), qatan2(b, a) / n).
*/
n = qilog2(epsilon);
epsilon2 = qbitvalue(n - 4);
tmp1 = qsquare(c->real);
tmp2 = qsquare(c->imag);
a2pb2 = qqadd(tmp1, tmp2);
qfree(tmp1);
qfree(tmp2);
tmp1 = qscale(q, 1L);
root = qroot(a2pb2, tmp1, epsilon2);
qfree(a2pb2);
qfree(tmp1);
m = qilog2(root);
if (m < n) {
qfree(root);
return clink(&_czero_);
}
qfree(epsilon2);
epsilon2 = qbitvalue(n - m - 4);
tmp1 = qatan2(c->imag, c->real, epsilon2);
qfree(epsilon2);
tmp2 = qdiv(tmp1, q);
qfree(tmp1);
r = cpolar(root, tmp2, epsilon);
qfree(root);
qfree(tmp2);
return r;
}
/*
* Calculate the complex exponential function to the desired accuracy.
* We use the formula:
* exp(a + bi) = exp(a) * (cos(b) + i * sin(b)).
*/
COMPLEX *
cexp(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *r;
NUMBER *sin, *cos, *tmp1, *tmp2, *epsilon1;
long k, n;
if (qiszero(epsilon)) {
math_error("Zero epsilon for cexp");
/*NOTREACHED*/
}
r = comalloc();
if (cisreal(c)) {
r->real = qexp(c->real, epsilon);
return r;
}
n = qilog2(epsilon);
epsilon1 = qbitvalue(n - 2);
tmp1 = qexp(c->real, epsilon1);
qfree(epsilon1);
if (qiszero(tmp1)) {
qfree(tmp1);
return clink(&_czero_);
}
k = qilog2(tmp1) + 1;
if (k < n) {
qfree(tmp1);
return clink(&_czero_);
}
qsincos(c->imag, k - n + 2, &sin, &cos);
tmp2 = qmul(tmp1, cos);
qfree(cos);
r->real = qmappr(tmp2, epsilon, 24L);
qfree(tmp2);
tmp2 = qmul(tmp1, sin);
qfree(tmp1);
qfree(sin);
r->imag = qmappr(tmp2, epsilon, 24L);
qfree(tmp2);
return r;
}
/*
* Calculate the natural logarithm of a complex number within the specified
* error. We use the formula:
* ln(a + bi) = ln(a^2 + b^2) / 2 + i * atan2(b, a).
*/
COMPLEX *
cln(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *r;
NUMBER *a2b2, *tmp1, *tmp2, *epsilon1;
if (ciszero(c)) {
math_error("Logarithm of zero");
/*NOTREACHED*/
}
if (cisone(c))
return clink(&_czero_);
r = comalloc();
if (cisreal(c) && !qisneg(c->real)) {
r->real = qln(c->real, epsilon);
return r;
}
tmp1 = qsquare(c->real);
tmp2 = qsquare(c->imag);
a2b2 = qqadd(tmp1, tmp2);
qfree(tmp1);
qfree(tmp2);
epsilon1 = qscale(epsilon, 1L);
tmp1 = qln(a2b2, epsilon1);
qfree(a2b2);
qfree(epsilon1);
r->real = qscale(tmp1, -1L);
qfree(tmp1);
r->imag = qatan2(c->imag, c->real, epsilon);
return r;
}
/*
* Calculate the complex cosine within the specified accuracy.
* This uses the formula:
* cos(x) = (exp(1i * x) + exp(-1i * x))/2;
*/
COMPLEX *
ccos(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *r, *ctmp1, *ctmp2, *ctmp3;
NUMBER *epsilon1;
long n;
BOOL neg;
if (qiszero(epsilon)) {
math_error("Zero epsilon for ccos");
/*NOTREACHED*/
}
n = qilog2(epsilon);
ctmp1 = comalloc();
neg = qisneg(c->imag);
ctmp1->real = neg ? qneg(c->imag) : qlink(c->imag);
ctmp1->imag = neg ? qlink(c->real) : qneg(c->real);
epsilon1 = qbitvalue(n - 2);
ctmp2 = cexp(ctmp1, epsilon1);
comfree(ctmp1);
qfree(epsilon1);
if (ciszero(ctmp2)) {
comfree(ctmp2);
return clink(&_czero_);
}
ctmp1 = cinv(ctmp2);
ctmp3 = cadd(ctmp2, ctmp1);
comfree(ctmp1);
comfree(ctmp2);
ctmp1 = cscale(ctmp3, -1);
comfree(ctmp3);
r = comalloc();
r->real = qmappr(ctmp1->real, epsilon, 24L);
r->imag = qmappr(ctmp1->imag, epsilon, 24L);
comfree(ctmp1);
return r;
}
/*
* Calculate the complex sine within the specified accuracy.
* This uses the formula:
* sin(x) = (exp(1i * x) - exp(-i1*x))/(2i).
*/
COMPLEX *
csin(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *r, *ctmp1, *ctmp2, *ctmp3;
NUMBER *qtmp, *epsilon1;
long n;
BOOL neg;
if (qiszero(epsilon)) {
math_error("Zero epsilon for csin");
/*NOTREACHED*/
}
if (ciszero(c))
return clink(&_czero_);
n = qilog2(epsilon);
ctmp1 = comalloc();
neg = qisneg(c->imag);
ctmp1->real = neg ? qneg(c->imag) : qlink(c->imag);
ctmp1->imag = neg ? qlink(c->real) : qneg(c->real);
epsilon1 = qbitvalue(n - 2);
ctmp2 = cexp(ctmp1, epsilon1);
comfree(ctmp1);
qfree(epsilon1);
if (ciszero(ctmp2)) {
comfree(ctmp2);
return clink(&_czero_);
}
ctmp1 = cinv(ctmp2);
ctmp3 = csub(ctmp2, ctmp1);
comfree(ctmp1);
comfree(ctmp2);
ctmp1 = cscale(ctmp3, -1);
comfree(ctmp3);
r = comalloc();
qtmp = neg ? qlink(ctmp1->imag) : qneg(ctmp1->imag);
r->real = qmappr(qtmp, epsilon, 24L);
qfree(qtmp);
qtmp = neg ? qneg(ctmp1->real) : qlink(ctmp1->real);
r->imag = qmappr(qtmp, epsilon, 24L);
qfree(qtmp);
comfree(ctmp1);
return r;
}
/*
* Convert a number from polar coordinates to normal complex number form
* within the specified accuracy. This produces the value:
* q1 * cos(q2) + q1 * sin(q2) * i.
*/
COMPLEX *
cpolar(NUMBER *q1, NUMBER *q2, NUMBER *epsilon)
{
COMPLEX *r;
NUMBER *tmp, *cos, *sin;
long m, n;
if (qiszero(epsilon)) {
math_error("Zero epsilson for cpolar");
/*NOTREACHED*/
}
if (qiszero(q1))
return qlink(&_czero_);
m = qilog2(q1) + 1;
n = qilog2(epsilon);
if (m < n)
return qlink(&_czero_);
r = comalloc();
if (qiszero(q2)) {
r->real = qlink(q1);
return r;
}
qsincos(q2, m - n + 2, &sin, &cos);
tmp = qmul(q1, cos);
qfree(cos);
r->real = qmappr(tmp, epsilon, 24L);
qfree(tmp);
tmp = qmul(q1, sin);
qfree(sin);
r->imag = qmappr(tmp, epsilon, 24L);
qfree(tmp);
return r;
}
/*
* Raise one complex number to the power of another one to within the
* specified error.
*/
COMPLEX *
cpower(COMPLEX *c1, COMPLEX *c2, NUMBER *epsilon)
{
COMPLEX *ctmp1, *ctmp2;
long k1, k2, k, m1, m2, m, n;
NUMBER *a2b2, *qtmp1, *qtmp2, *epsilon1;
if (qiszero(epsilon)) {
math_error("Zero epsilon for cpower");
/*NOTREACHED*/
}
if (ciszero(c1)) {
if (qisneg(c2->real) || qiszero(c2->real)) {
math_error ("Non-positive exponent of zero");
/*NOTREACHED*/
}
return clink(&_czero_);
}
n = qilog2(epsilon);
m1 = m2 = -1000000;
k1 = k2 = 0;
qtmp1 = qsquare(c1->real);
qtmp2 = qsquare(c1->imag);
a2b2 = qqadd(qtmp1, qtmp2);
qfree(qtmp1);
qfree(qtmp2);
if (!qiszero(c2->real)) {
m1 = qilog2(c2->real);
epsilon1 = qbitvalue(-m1 - 1);
qtmp1 = qln(a2b2, epsilon1);
qfree(epsilon1);
qfree(a2b2);
qtmp2 = qmul(qtmp1, c2->real);
qfree(qtmp1);
qtmp1 = qmul(qtmp2, &_qlge_);
qfree(qtmp2);
k1 = qtoi(qtmp1);
qfree(qtmp1);
}
if (!qiszero(c2->imag)) {
m2 = qilog2(c2->imag);
epsilon1 = qbitvalue(-m2 - 1);
qtmp1 = qatan2(c1->imag, c1->real, epsilon1);
qfree(epsilon1);
qtmp2 = qmul(qtmp1, c2->imag);
qfree(qtmp1);
qtmp1 = qscale(qtmp2, -1);
qfree(qtmp2);
qtmp2 = qmul(qtmp1, &_qlge_);
qfree(qtmp1);
k2 = qtoi(qtmp2);
qfree(qtmp2);
}
m = (m2 > m1) ? m2 : m1;
k = k1 - k2 + 1;
if (k < n)
return clink(&_czero_);
epsilon1 = qbitvalue(n - k - m - 2);
ctmp1 = cln(c1, epsilon1);
qfree(epsilon1);
ctmp2 = cmul(ctmp1, c2);
comfree(ctmp1);
ctmp1 = cexp(ctmp2, epsilon);
comfree(ctmp2);
return ctmp1;
}
/*
* Print a complex number in the current output mode.
*/
void
comprint(COMPLEX *c)
{
NUMBER qtmp;
if (conf->outmode == MODE_FRAC) {
cprintfr(c);
return;
}
if (!qiszero(c->real) || qiszero(c->imag))
qprintnum(c->real, MODE_DEFAULT);
qtmp = c->imag[0];
if (qiszero(&qtmp))
return;
if (!qiszero(c->real) && !qisneg(&qtmp))
math_chr('+');
if (qisneg(&qtmp)) {
math_chr('-');
qtmp.num.sign = 0;
}
qprintnum(&qtmp, MODE_DEFAULT);
math_chr('i');
}
/*
* Print a complex number in rational representation.
* Example: 2/3-4i/5
*/
void
cprintfr(COMPLEX *c)
{
NUMBER *r;
NUMBER *i;
r = c->real;
i = c->imag;
if (!qiszero(r) || qiszero(i))
qprintfr(r, 0L, FALSE);
if (qiszero(i))
return;
if (!qiszero(r) && !qisneg(i))
math_chr('+');
zprintval(i->num, 0L, 0L);
math_chr('i');
if (qisfrac(i)) {
math_chr('/');
zprintval(i->den, 0L, 0L);
}
}
/* END CODE */

555
commath.c Normal file
View File

@@ -0,0 +1,555 @@
/*
* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Extended precision complex arithmetic primitive routines
*/
#include "cmath.h"
COMPLEX _czero_ = { &_qzero_, &_qzero_, 1 };
COMPLEX _cone_ = { &_qone_, &_qzero_, 1 };
COMPLEX _conei_ = { &_qzero_, &_qone_, 1 };
static COMPLEX _cnegone_ = { &_qnegone_, &_qzero_, 1 };
/*
* Add two complex numbers.
*/
COMPLEX *
cadd(COMPLEX *c1, COMPLEX *c2)
{
COMPLEX *r;
if (ciszero(c1))
return clink(c2);
if (ciszero(c2))
return clink(c1);
r = comalloc();
if (!qiszero(c1->real) || !qiszero(c2->real))
r->real = qqadd(c1->real, c2->real);
if (!qiszero(c1->imag) || !qiszero(c2->imag))
r->imag = qqadd(c1->imag, c2->imag);
return r;
}
/*
* Subtract two complex numbers.
*/
COMPLEX *
csub(COMPLEX *c1, COMPLEX *c2)
{
COMPLEX *r;
if ((c1->real == c2->real) && (c1->imag == c2->imag))
return clink(&_czero_);
if (ciszero(c2))
return clink(c1);
r = comalloc();
if (!qiszero(c1->real) || !qiszero(c2->real))
r->real = qsub(c1->real, c2->real);
if (!qiszero(c1->imag) || !qiszero(c2->imag))
r->imag = qsub(c1->imag, c2->imag);
return r;
}
/*
* Multiply two complex numbers.
* This saves one multiplication over the obvious algorithm by
* trading it for several extra additions, as follows. Let
* q1 = (a + b) * (c + d)
* q2 = a * c
* q3 = b * d
* Then (a+bi) * (c+di) = (q2 - q3) + (q1 - q2 - q3)i.
*/
COMPLEX *
cmul(COMPLEX *c1, COMPLEX *c2)
{
COMPLEX *r;
NUMBER *q1, *q2, *q3, *q4;
if (ciszero(c1) || ciszero(c2))
return clink(&_czero_);
if (cisone(c1))
return clink(c2);
if (cisone(c2))
return clink(c1);
if (cisreal(c2))
return cmulq(c1, c2->real);
if (cisreal(c1))
return cmulq(c2, c1->real);
/*
* Need to do the full calculation.
*/
r = comalloc();
q2 = qqadd(c1->real, c1->imag);
q3 = qqadd(c2->real, c2->imag);
q1 = qmul(q2, q3);
qfree(q2);
qfree(q3);
q2 = qmul(c1->real, c2->real);
q3 = qmul(c1->imag, c2->imag);
q4 = qqadd(q2, q3);
r->real = qsub(q2, q3);
r->imag = qsub(q1, q4);
qfree(q1);
qfree(q2);
qfree(q3);
qfree(q4);
return r;
}
/*
* Square a complex number.
*/
COMPLEX *
csquare(COMPLEX *c)
{
COMPLEX *r;
NUMBER *q1, *q2;
if (ciszero(c))
return clink(&_czero_);
if (cisrunit(c))
return clink(&_cone_);
if (cisiunit(c))
return clink(&_cnegone_);
r = comalloc();
if (cisreal(c)) {
r->real = qsquare(c->real);
return r;
}
if (cisimag(c)) {
q1 = qsquare(c->imag);
r->real = qneg(q1);
qfree(q1);
return r;
}
q1 = qsquare(c->real);
q2 = qsquare(c->imag);
r->real = qsub(q1, q2);
qfree(q1);
qfree(q2);
q1 = qmul(c->real, c->imag);
r->imag = qscale(q1, 1L);
qfree(q1);
return r;
}
/*
* Divide two complex numbers.
*/
COMPLEX *
cdiv(COMPLEX *c1, COMPLEX *c2)
{
COMPLEX *r;
NUMBER *q1, *q2, *q3, *den;
if (ciszero(c2)) {
math_error("Division by zero");
/*NOTREACHED*/
}
if ((c1->real == c2->real) && (c1->imag == c2->imag))
return clink(&_cone_);
r = comalloc();
if (cisreal(c1) && cisreal(c2)) {
r->real = qdiv(c1->real, c2->real);
return r;
}
if (cisimag(c1) && cisimag(c2)) {
r->real = qdiv(c1->imag, c2->imag);
return r;
}
if (cisimag(c1) && cisreal(c2)) {
r->imag = qdiv(c1->imag, c2->real);
return r;
}
if (cisreal(c1) && cisimag(c2)) {
q1 = qdiv(c1->real, c2->imag);
r->imag = qneg(q1);
qfree(q1);
return r;
}
if (cisreal(c2)) {
r->real = qdiv(c1->real, c2->real);
r->imag = qdiv(c1->imag, c2->real);
return r;
}
q1 = qsquare(c2->real);
q2 = qsquare(c2->imag);
den = qqadd(q1, q2);
qfree(q1);
qfree(q2);
q1 = qmul(c1->real, c2->real);
q2 = qmul(c1->imag, c2->imag);
q3 = qqadd(q1, q2);
qfree(q1);
qfree(q2);
r->real = qdiv(q3, den);
qfree(q3);
q1 = qmul(c1->real, c2->imag);
q2 = qmul(c1->imag, c2->real);
q3 = qsub(q2, q1);
qfree(q1);
qfree(q2);
r->imag = qdiv(q3, den);
qfree(q3);
qfree(den);
return r;
}
/*
* Invert a complex number.
*/
COMPLEX *
cinv(COMPLEX *c)
{
COMPLEX *r;
NUMBER *q1, *q2, *den;
if (ciszero(c)) {
math_error("Inverting zero");
/*NOTREACHED*/
}
r = comalloc();
if (cisreal(c)) {
r->real = qinv(c->real);
return r;
}
if (cisimag(c)) {
q1 = qinv(c->imag);
r->imag = qneg(q1);
qfree(q1);
return r;
}
q1 = qsquare(c->real);
q2 = qsquare(c->imag);
den = qqadd(q1, q2);
qfree(q1);
qfree(q2);
r->real = qdiv(c->real, den);
q1 = qdiv(c->imag, den);
r->imag = qneg(q1);
qfree(q1);
qfree(den);
return r;
}
/*
* Negate a complex number.
*/
COMPLEX *
cneg(COMPLEX *c)
{
COMPLEX *r;
if (ciszero(c))
return clink(&_czero_);
r = comalloc();
if (!qiszero(c->real))
r->real = qneg(c->real);
if (!qiszero(c->imag))
r->imag = qneg(c->imag);
return r;
}
/*
* Take the integer part of a complex number.
* This means take the integer part of both components.
*/
COMPLEX *
cint(COMPLEX *c)
{
COMPLEX *r;
if (cisint(c))
return clink(c);
r = comalloc();
r->real = qint(c->real);
r->imag = qint(c->imag);
return r;
}
/*
* Take the fractional part of a complex number.
* This means take the fractional part of both components.
*/
COMPLEX *
cfrac(COMPLEX *c)
{
COMPLEX *r;
if (cisint(c))
return clink(&_czero_);
r = comalloc();
r->real = qfrac(c->real);
r->imag = qfrac(c->imag);
return r;
}
/*
* Take the conjugate of a complex number.
* This negates the complex part.
*/
COMPLEX *
cconj(COMPLEX *c)
{
COMPLEX *r;
if (cisreal(c))
return clink(c);
r = comalloc();
if (!qiszero(c->real))
r->real = qlink(c->real);
r->imag = qneg(c->imag);
return r;
}
/*
* Return the real part of a complex number.
*/
COMPLEX *
creal(COMPLEX *c)
{
COMPLEX *r;
if (cisreal(c))
return clink(c);
r = comalloc();
if (!qiszero(c->real))
r->real = qlink(c->real);
return r;
}
/*
* Return the imaginary part of a complex number as a real.
*/
COMPLEX *
cimag(COMPLEX *c)
{
COMPLEX *r;
if (cisreal(c))
return clink(&_czero_);
r = comalloc();
r->real = qlink(c->imag);
return r;
}
/*
* Add a real number to a complex number.
*/
COMPLEX *
caddq(COMPLEX *c, NUMBER *q)
{
COMPLEX *r;
if (qiszero(q))
return clink(c);
r = comalloc();
r->real = qqadd(c->real, q);
r->imag = qlink(c->imag);
return r;
}
/*
* Subtract a real number from a complex number.
*/
COMPLEX *
csubq(COMPLEX *c, NUMBER *q)
{
COMPLEX *r;
if (qiszero(q))
return clink(c);
r = comalloc();
r->real = qsub(c->real, q);
r->imag = qlink(c->imag);
return r;
}
/*
* Shift the components of a complex number left by the specified
* number of bits. Negative values shift to the right.
*/
COMPLEX *
cshift(COMPLEX *c, long n)
{
COMPLEX *r;
if (ciszero(c) || (n == 0))
return clink(c);
r = comalloc();
r->real = qshift(c->real, n);
r->imag = qshift(c->imag, n);
return r;
}
/*
* Scale a complex number by a power of two.
*/
COMPLEX *
cscale(COMPLEX *c, long n)
{
COMPLEX *r;
if (ciszero(c) || (n == 0))
return clink(c);
r = comalloc();
r->real = qscale(c->real, n);
r->imag = qscale(c->imag, n);
return r;
}
/*
* Multiply a complex number by a real number.
*/
COMPLEX *
cmulq(COMPLEX *c, NUMBER *q)
{
COMPLEX *r;
if (qiszero(q))
return clink(&_czero_);
if (qisone(q))
return clink(c);
if (qisnegone(q))
return cneg(c);
r = comalloc();
r->real = qmul(c->real, q);
r->imag = qmul(c->imag, q);
return r;
}
/*
* Divide a complex number by a real number.
*/
COMPLEX *
cdivq(COMPLEX *c, NUMBER *q)
{
COMPLEX *r;
if (qiszero(q)) {
math_error("Division by zero");
/*NOTREACHED*/
}
if (qisone(q))
return clink(c);
if (qisnegone(q))
return cneg(c);
r = comalloc();
r->real = qdiv(c->real, q);
r->imag = qdiv(c->imag, q);
return r;
}
/*
* Construct a complex number given the real and imaginary components.
*/
COMPLEX *
qqtoc(NUMBER *q1, NUMBER *q2)
{
COMPLEX *r;
if (qiszero(q1) && qiszero(q2))
return clink(&_czero_);
r = comalloc();
if (!qiszero(q1))
r->real = qlink(q1);
if (!qiszero(q2))
r->imag = qlink(q2);
return r;
}
/*
* Compare two complex numbers for equality, returning FALSE if they are equal,
* and TRUE if they differ.
*/
BOOL
ccmp(COMPLEX *c1, COMPLEX *c2)
{
BOOL i;
i = qcmp(c1->real, c2->real);
if (!i)
i = qcmp(c1->imag, c2->imag);
return i;
}
/*
* Compare two complex numbers and return a complex number with real and
* imaginary parts -1, 0 or 1 indicating relative values of the real and
* imaginary parts of the two numbers.
*/
COMPLEX *
crel(COMPLEX *c1, COMPLEX *c2)
{
COMPLEX *c;
c = comalloc();
c->real = itoq((long) qrel(c1->real, c2->real));
c->imag = itoq((long) qrel(c1->imag, c2->imag));
return c;
}
/*
* Allocate a new complex number.
*/
COMPLEX *
comalloc(void)
{
COMPLEX *r;
r = (COMPLEX *) malloc(sizeof(COMPLEX));
if (r == NULL) {
math_error("Cannot allocate complex number");
/*NOTREACHED*/
}
r->links = 1;
r->real = qlink(&_qzero_);
r->imag = qlink(&_qzero_);
return r;
}
/*
* Free a complex number.
*/
void
comfree(COMPLEX *c)
{
if (--(c->links) > 0)
return;
qfree(c->real);
qfree(c->imag);
free(c);
}
/* END CODE */

985
config.c Normal file
View File

@@ -0,0 +1,985 @@
/*
* Copyright (c) 1995 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Configuration routines.
*/
#include "calc.h"
#include "token.h"
#include "zrand.h"
/*
* Table of configuration types that can be set or read.
*/
NAMETYPE configs[] = {
{"all", CONFIG_ALL},
{"mode", CONFIG_MODE},
{"display", CONFIG_DISPLAY},
{"epsilon", CONFIG_EPSILON},
/*epsilonprec -- tied to epsilon not a configuration type*/
{"trace", CONFIG_TRACE},
{"maxprint", CONFIG_MAXPRINT},
{"mul2", CONFIG_MUL2},
{"sq2", CONFIG_SQ2},
{"pow2", CONFIG_POW2},
{"redc2", CONFIG_REDC2},
{"tilde", CONFIG_TILDE},
{"tab", CONFIG_TAB},
{"quomod", CONFIG_QUOMOD},
{"quo", CONFIG_QUO},
{"mod", CONFIG_MOD},
{"sqrt", CONFIG_SQRT},
{"appr", CONFIG_APPR},
{"cfappr", CONFIG_CFAPPR},
{"cfsim", CONFIG_CFSIM},
{"outround", CONFIG_OUTROUND},
{"round", CONFIG_ROUND},
{"leadzero", CONFIG_LEADZERO},
{"fullzero", CONFIG_FULLZERO},
{"maxerr", CONFIG_MAXERR},
{"prompt", CONFIG_PROMPT},
{"more", CONFIG_MORE},
{"random", CONFIG_RANDOM},
{NULL, 0}
};
/*
* configurations
*/
CONFIG oldstd = { /* backward compatible standard configuration */
MODE_INITIAL, /* current output mode */
20, /* current output digits for float or exp */
NULL, /* loaded in at startup - default error for real functions */
EPSILONPREC_DEFAULT, /* binary precision of epsilon */
FALSE, /* tracing flags */
MAXPRINT_DEFAULT, /* number of elements to print */
MUL_ALG2, /* size of number to use multiply alg 2 */
SQ_ALG2, /* size of number to use square alg 2 */
POW_ALG2, /* size of modulus to use REDC for powers */
REDC_ALG2, /* size of modulus to use REDC algorithm 2 */
TRUE, /* ok to print a tilde on aproximations */
TRUE, /* ok to print tab before numeric values */
0, /* quomod() default rounding mode */
2, /* quotent // default rounding mode */
0, /* mod % default rounding mode */
24, /* sqrt() default rounding mode */
24, /* appr() default rounding mode */
0, /* cfappr() default rounding mode */
8, /* cfsim() default rounding mode */
2, /* output default rounding mode */
24, /* round()/bround() default rounding mode */
FALSE, /* ok to print leading 0 before decimal pt */
0, /* ok to print trailing 0's */
MAXERRORCOUNT, /* max errors before abort */
PROMPT1, /* normal prompt */
PROMPT2, /* prompt when inside multi-line input */
3 /* require 1 mod 4 and to pass ptest(newn,1) */
};
CONFIG newstd = { /* new non-backward compatible configuration */
MODE_INITIAL, /* current output mode */
10, /* current output digits for float or exp */
NULL, /* loaded in at startup - default error for real functions */
NEW_EPSILONPREC_DEFAULT, /* binary precision of epsilon */
FALSE, /* tracing flags */
MAXPRINT_DEFAULT, /* number of elements to print */
MUL_ALG2, /* size of number to use multiply alg 2 */
SQ_ALG2, /* size of number to use square alg 2 */
POW_ALG2, /* size of modulus to use REDC for powers */
REDC_ALG2, /* size of modulus to use REDC algorithm 2 */
TRUE, /* ok to print a tilde on aproximations */
TRUE, /* ok to print tab before numeric values */
0, /* quomod() default rounding mode */
0, /* quotent // default rounding mode */
0, /* mod % default rounding mode */
24, /* sqrt() default rounding mode */
24, /* appr() default rounding mode */
0, /* cfappr() default rounding mode */
8, /* cfsim() default rounding mode */
24, /* output default rounding mode */
24, /* round()/bround() default rounding mode */
TRUE, /* ok to print leading 0 before decimal pt */
1, /* ok to print trailing 0's */
MAXERRORCOUNT, /* max errors before abort */
"; ", /* normal prompt */
";; ", /* prompt when inside multi-line input */
3 /* require 1 mod 4 and to pass ptest(newn,1) */
};
CONFIG *conf = NULL; /* loaded in at startup - current configuration */
/*
* Possible output modes.
*/
static NAMETYPE modes[] = {
{"frac", MODE_FRAC},
{"decimal", MODE_FRAC},
{"dec", MODE_FRAC},
{"int", MODE_INT},
{"real", MODE_REAL},
{"exp", MODE_EXP},
{"hexadecimal", MODE_HEX},
{"hex", MODE_HEX},
{"octal", MODE_OCTAL},
{"oct", MODE_OCTAL},
{"binary", MODE_BINARY},
{"bin", MODE_BINARY},
{NULL, 0}
};
/*
* Possible binary config state values
*/
static NAMETYPE truth[] = {
{"y", TRUE},
{"n", FALSE},
{"yes", TRUE},
{"no", FALSE},
{"set", TRUE},
{"unset", FALSE},
{"on", TRUE},
{"off", FALSE},
{"true", TRUE},
{"false", FALSE},
{"t", TRUE},
{"f", FALSE},
{"1", TRUE},
{"0", FALSE},
{NULL, 0}
};
/*
* declate static functions
*/
static int modetype(char *name);
static int truthtype(char *name);
static char *modename(int type);
/*
* Given a string value which represents a configuration name, return
* the configuration type for that string. Returns negative type if
* the string is unknown.
*
* given:
* name configuration name
*/
int
configtype(char *name)
{
NAMETYPE *cp; /* current config pointer */
for (cp = configs; cp->name; cp++) {
if (strcmp(cp->name, name) == 0)
return cp->type;
}
return -1;
}
/*
* Given the name of a mode, convert it to the internal format.
* Returns -1 if the string is unknown.
*
* given:
* name mode name
*/
static int
modetype(char *name)
{
NAMETYPE *cp; /* current config pointer */
for (cp = modes; cp->name; cp++) {
if (strcmp(cp->name, name) == 0)
return cp->type;
}
return -1;
}
/*
* Given the name of a truth value, convert it to a BOOL or -1.
* Returns -1 if the string is unknown.
*
* given:
* name mode name
*/
static int
truthtype(char *name)
{
NAMETYPE *cp; /* current config pointer */
for (cp = truth; cp->name; cp++) {
if (strcmp(cp->name, name) == 0)
return cp->type;
}
return -1;
}
/*
* Given the mode type, convert it to a string representing that mode.
* Where there are multiple strings representing the same mode, the first
* one in the table is used. Returns NULL if the node type is unknown.
* The returned string cannot be modified.
*/
static char *
modename(int type)
{
NAMETYPE *cp; /* current config pointer */
for (cp = modes; cp->name; cp++) {
if (type == cp->type)
return cp->name;
}
return NULL;
}
/*
* Set the specified configuration type to the specified value.
* An error is generated if the type number or value is illegal.
*/
void
setconfig(int type, VALUE *vp)
{
NUMBER *q;
CONFIG *newconf; /* new configuration to set */
long temp;
char *p;
switch (type) {
case CONFIG_ALL:
newconf = NULL; /* firewall */
if (vp->v_type == V_STR) {
if (strcmp(vp->v_str, "oldstd") == 0) {
newconf = &oldstd;
} else if (strcmp(vp->v_str, "newstd") == 0) {
newconf = &newstd;
} else {
math_error("CONFIG alias not oldstd or newstd");
/*NOTREACHED*/
}
} else if (vp->v_type != V_CONFIG) {
math_error("non-CONFIG for all");
/*NOTREACHED*/
} else {
newconf = vp->v_config;
}
/* free the current configuration */
config_free(conf);
/* set the new configuration */
conf = config_copy(newconf);
break;
case CONFIG_TRACE:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for trace");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || !zistiny(q->num) ||
((unsigned long) temp > TRACE_MAX)) {
math_error("Bad trace value");
/*NOTREACHED*/
}
conf->traceflags = (FLAG)temp;
break;
case CONFIG_DISPLAY:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for display");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num))
temp = -1;
math_setdigits(temp);
break;
case CONFIG_MODE:
if (vp->v_type != V_STR) {
math_error("Non-string for mode");
/*NOTREACHED*/
}
temp = modetype(vp->v_str);
if (temp < 0) {
math_error("Unknown mode \"%s\"", vp->v_str);
/*NOTREACHED*/
}
math_setmode((int) temp);
break;
case CONFIG_EPSILON:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for epsilon");
/*NOTREACHED*/
}
setepsilon(vp->v_num);
break;
case CONFIG_MAXPRINT:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for maxprint");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num))
temp = -1;
if (temp < 0) {
math_error("Maxprint value is out of range");
/*NOTREACHED*/
}
conf->maxprint = temp;
break;
case CONFIG_MUL2:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for mul2");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q))
temp = -1;
if (temp == 0)
temp = MUL_ALG2;
if (temp < 2) {
math_error("Illegal mul2 value");
/*NOTREACHED*/
}
conf->mul2 = (int)temp;
break;
case CONFIG_SQ2:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for sq2");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q))
temp = -1;
if (temp == 0)
temp = SQ_ALG2;
if (temp < 2) {
math_error("Illegal sq2 value");
/*NOTREACHED*/
}
conf->sq2 = (int)temp;
break;
case CONFIG_POW2:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for pow2");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q))
temp = -1;
if (temp == 0)
temp = POW_ALG2;
if (temp < 1) {
math_error("Illegal pow2 value");
/*NOTREACHED*/
}
conf->pow2 = (int)temp;
break;
case CONFIG_REDC2:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for redc2");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q))
temp = -1;
if (temp == 0)
temp = REDC_ALG2;
if (temp < 1) {
math_error("Illegal redc2 value");
/*NOTREACHED*/
}
conf->redc2 = (int)temp;
break;
case CONFIG_TILDE:
if (vp->v_type == V_NUM) {
q = vp->v_num;
conf->tilde_ok = !qiszero(q);
} else if (vp->v_type == V_STR) {
temp = truthtype(vp->v_str);
if (temp < 0) {
math_error("Illegal truth value");
/*NOTREACHED*/
}
conf->tilde_ok = (int)temp;
}
break;
case CONFIG_TAB:
if (vp->v_type == V_NUM) {
q = vp->v_num;
conf->tab_ok = !qiszero(q);
} else if (vp->v_type == V_STR) {
temp = truthtype(vp->v_str);
if (temp < 0) {
math_error("Illegal truth value");
/*NOTREACHED*/
}
conf->tab_ok = (int)temp;
}
break;
case CONFIG_QUOMOD:
if (vp->v_type != V_NUM) {
math_error("Non numeric for quomod");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal quomod parameter value");
/*NOTREACHED*/
}
conf->quomod = temp;
break;
case CONFIG_QUO:
if (vp->v_type != V_NUM) {
math_error("Non numeric for quo");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal quo parameter value");
/*NOTREACHED*/
}
conf->quo = temp;
break;
case CONFIG_MOD:
if (vp->v_type != V_NUM) {
math_error("Non numeric for mod");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal mod parameter value");
/*NOTREACHED*/
}
conf->mod = temp;
break;
case CONFIG_SQRT:
if (vp->v_type != V_NUM) {
math_error("Non numeric for sqrt");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal sqrt parameter value");
/*NOTREACHED*/
}
conf->sqrt = temp;
break;
case CONFIG_APPR:
if (vp->v_type != V_NUM) {
math_error("Non numeric for appr");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal appr parameter value");
/*NOTREACHED*/
}
conf->appr = temp;
break;
case CONFIG_CFAPPR:
if (vp->v_type != V_NUM) {
math_error("Non numeric for cfappr");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal cfappr parameter value");
/*NOTREACHED*/
}
conf->cfappr = temp;
break;
case CONFIG_CFSIM:
if (vp->v_type != V_NUM) {
math_error("Non numeric for cfsim");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal cfsim parameter value");
/*NOTREACHED*/
}
conf->cfsim = temp;
break;
case CONFIG_OUTROUND:
if (vp->v_type != V_NUM) {
math_error("Non numeric for outround");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal output parameter value");
/*NOTREACHED*/
}
conf->outround = temp;
break;
case CONFIG_ROUND:
if (vp->v_type != V_NUM) {
math_error("Non numeric for round");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num)) {
math_error("Illegal output parameter value");
/*NOTREACHED*/
}
conf->round = temp;
break;
case CONFIG_LEADZERO:
if (vp->v_type == V_NUM) {
q = vp->v_num;
conf->leadzero = !qiszero(q);
} else if (vp->v_type == V_STR) {
temp = truthtype(vp->v_str);
if (temp < 0) { {
math_error("Illegal truth value");
/*NOTREACHED*/
}
}
conf->leadzero = (int)temp;
}
break;
case CONFIG_FULLZERO:
if (vp->v_type == V_NUM) {
q = vp->v_num;
conf->fullzero = !qiszero(q);
} else if (vp->v_type == V_STR) {
temp = truthtype(vp->v_str);
if (temp < 0) { {
math_error("Illegal truth value");
/*NOTREACHED*/
}
}
conf->fullzero = (int)temp;
}
break;
case CONFIG_MAXERR:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for maxerr");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num))
temp = -1;
if (temp < 0) {
math_error("Maxerr value is out of range");
/*NOTREACHED*/
}
conf->maxerrorcount = temp;
break;
case CONFIG_PROMPT:
if (vp->v_type != V_STR) {
math_error("Non-string for prompt");
/*NOTREACHED*/
}
p = (char *)malloc(strlen(vp->v_str) + 1);
if (p == NULL) {
math_error("Cannot duplicate new prompt");
/*NOTREACHED*/
}
strcpy(p, vp->v_str);
free(conf->prompt1);
conf->prompt1 = p;
break;
case CONFIG_MORE:
if (vp->v_type != V_STR) {
math_error("Non-string for more prompt");
/*NOTREACHED*/
}
p = (char *)malloc(strlen(vp->v_str) + 1);
if (p == NULL) {
math_error("Cannot duplicate new more prompt");
/*NOTREACHED*/
}
strcpy(p, vp->v_str);
free(conf->prompt2);
conf->prompt2 = p;
break;
case CONFIG_RANDOM:
if (vp->v_type != V_NUM) {
math_error("Non-numeric for random config value");
/*NOTREACHED*/
}
q = vp->v_num;
temp = qtoi(q);
if (qisfrac(q) || qisneg(q) || !zistiny(q->num))
temp = -1;
if (temp < BLUM_CFG_MIN || temp > BLUM_CFG_MAX) {
math_error("Random config value is out of range");
/*NOTREACHED*/
}
conf->random = temp;
break;
default:
math_error("Setting illegal config parameter");
/*NOTREACHED*/
}
}
/*
* config_copy - copy the configuration from one value to another
*
* given:
* src copy this configuration
*
* returns:
* prointer to the configuration copy
*/
CONFIG *
config_copy(CONFIG *src)
{
CONFIG *dest; /* the new CONFIG to return */
/*
* firewall
*/
if (src == NULL || src->epsilon == NULL || src->prompt1 == NULL ||
src->prompt2 == NULL) {
math_error("bad CONFIG value");
/*NOTREACHED*/
}
/*
* malloc the storage
*/
dest = (CONFIG *)malloc(sizeof(CONFIG));
if (dest == NULL) {
math_error("malloc of CONFIG failed");
/*NOTREACHED*/
}
/*
* copy over the values
*/
*dest = *src;
/*
* clone the pointer values
*/
dest->epsilon = qlink(src->epsilon);
dest->prompt1 = (char *)malloc(strlen(src->prompt1)+1);
if (dest->prompt1 == NULL) {
math_error("cannot dup prompt1 for new CONFIG value");
/*NOTREACHED*/
}
strcpy(dest->prompt1, src->prompt1);
dest->prompt2 = (char *)malloc(strlen(src->prompt2)+1);
if (dest->prompt2 == NULL) {
math_error("cannot dup prompt2 for new CONFIG value");
/*NOTREACHED*/
}
strcpy(dest->prompt2, src->prompt2);
/*
* return the new value
*/
return dest;
}
/*
* config_free - free a CONFIG value
*
* given:
* cfg the CONFIG value to free
*/
void
config_free(CONFIG *cfg)
{
/*
* firewall
*/
if (cfg == NULL) {
return;
}
/*
* free prointer values
*/
if (cfg->epsilon != NULL) {
qfree(cfg->epsilon);
}
if (cfg->prompt1 != NULL) {
free(cfg->prompt1);
}
if (cfg->prompt2 != NULL) {
free(cfg->prompt2);
}
/*
* free the CONFIG value itself
*/
free(cfg);
return;
}
/*
* config_value - return a CONFIG element as a value
*
* given:
* cfg CONFIG from which an element will be returned
* type the type of CONFIG element to print
* ret where to return the value
*
* returns:
* ret points to the VALUE returned
*/
void
config_value(CONFIG *cfg, int type, VALUE *vp)
{
long i=0;
/*
* firewall
*/
if (cfg == NULL || cfg->epsilon == NULL || cfg->prompt1 == NULL ||
cfg->prompt2 == NULL) {
math_error("bad CONFIG value");
/*NOTREACHED*/
}
/*
* convert element to value
*/
vp->v_type = V_NUM;
switch (type) {
case CONFIG_ALL:
vp->v_type = V_CONFIG;
vp->v_config = config_copy(conf);
return;
case CONFIG_TRACE:
i = cfg->traceflags;
break;
case CONFIG_DISPLAY:
i = cfg->outdigits;
break;
case CONFIG_MODE:
vp->v_type = V_STR;
vp->v_subtype = V_STRLITERAL;
vp->v_str = modename(cfg->outmode);
return;
case CONFIG_EPSILON:
vp->v_num = qlink(cfg->epsilon);
return;
case CONFIG_MAXPRINT:
i = cfg->maxprint;
break;
case CONFIG_MUL2:
i = cfg->mul2;
break;
case CONFIG_SQ2:
i = cfg->sq2;
break;
case CONFIG_POW2:
i = cfg->pow2;
break;
case CONFIG_REDC2:
i = cfg->redc2;
break;
case CONFIG_TILDE:
i = cfg->tilde_ok;
break;
case CONFIG_TAB:
i = cfg->tab_ok;
break;
case CONFIG_QUOMOD:
i = cfg->quomod;
break;
case CONFIG_QUO:
i = cfg->quo;
break;
case CONFIG_MOD:
i = cfg->mod;
break;
case CONFIG_SQRT:
i = cfg->sqrt;
break;
case CONFIG_APPR:
i = cfg->appr;
break;
case CONFIG_CFAPPR:
i = cfg->cfappr;
break;
case CONFIG_CFSIM:
i = cfg->cfsim;
break;
case CONFIG_OUTROUND:
i = cfg->outround;
break;
case CONFIG_ROUND:
i = cfg->round;
break;
case CONFIG_LEADZERO:
i = cfg->leadzero;
break;
case CONFIG_FULLZERO:
i = cfg->fullzero;
break;
case CONFIG_MAXERR:
i = cfg->maxerrorcount;
break;
case CONFIG_PROMPT:
vp->v_type = V_STR;
vp->v_subtype = V_STRLITERAL;
vp->v_str = cfg->prompt1;
return;
case CONFIG_MORE:
vp->v_type = V_STR;
vp->v_subtype = V_STRLITERAL;
vp->v_str = cfg->prompt2;
return;
case CONFIG_RANDOM:
i = cfg->random;
break;
default:
math_error("Getting illegal CONFIG element");
/*NOTREACHED*/
}
/*
* if we got this far, we have a V_NUM in i
*/
vp->v_num = itoq(i);
return;
}
/*
* config_cmp - compare two CONFIG states
*
* given:
* cfg1 - 1st CONFIG to compare
* cfg2 - 2nd CONFIG to compare
*
* return:
* TRUE if configurations differ
*/
BOOL
config_cmp(CONFIG *cfg1, CONFIG *cfg2)
{
/*
* firewall
*/
if (cfg1 == NULL || cfg1->epsilon == NULL || cfg1->prompt1 == NULL ||
cfg1->prompt2 == NULL) {
math_error("CONFIG #1 value is invaid");
/*NOTREACHED*/
}
if (cfg2 == NULL || cfg2->epsilon == NULL || cfg2->prompt1 == NULL ||
cfg2->prompt2 == NULL) {
math_error("CONFIG #2 value is invaid");
/*NOTREACHED*/
}
/*
* compare
*/
return cfg1->traceflags != cfg2->traceflags ||
cfg1->outdigits != cfg2->outdigits ||
cfg1->outmode != cfg2->outmode ||
qcmp(cfg1->epsilon, cfg2->epsilon) ||
cfg1->epsilonprec != cfg2->epsilonprec ||
cfg1->maxprint != cfg2->maxprint ||
cfg1->mul2 != cfg2->mul2 ||
cfg1->sq2 != cfg2->sq2 ||
cfg1->pow2 != cfg2->pow2 ||
cfg1->redc2 != cfg2->redc2 ||
cfg1->tilde_ok != cfg2->tilde_ok ||
cfg1->tab_ok != cfg2->tab_ok ||
cfg1->quomod != cfg2->quomod ||
cfg1->quo != cfg2->quo ||
cfg1->mod != cfg2->mod ||
cfg1->sqrt != cfg2->sqrt ||
cfg1->appr != cfg2->appr ||
cfg1->cfappr != cfg2->cfappr ||
cfg1->cfsim != cfg2->cfsim ||
cfg1->outround != cfg2->outround ||
cfg1->round != cfg2->round ||
cfg1->leadzero != cfg2->leadzero ||
cfg1->fullzero != cfg2->fullzero ||
cfg1->maxerrorcount != cfg2->maxerrorcount ||
strcmp(cfg1->prompt1, cfg2->prompt1) != 0 ||
strcmp(cfg1->prompt2, cfg2->prompt2) != 0 ||
cfg1->random != cfg2->random;
}

143
config.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* Prior to calc 2.9.3t9, these routines existed as a calc library called
* cryrand.cal. They have been rewritten in C for performance as well
* as to make them available directly from libcalc.a.
*
* Comments, suggestions, bug fixes and questions about these routines
* are welcome. Send EMail to the address given below.
*
* Happy bit twiddling,
*
* Landon Curt Noll
*
* chongo@toad.com
* ...!{pyramid,sun,uunet}!hoptoad!chongo
*
* chongo was here /\../\
*/
#if !defined(CONFIG_H)
#define CONFIG_H
#include "qmath.h"
/*
* configuration element types
*/
#define CONFIG_ALL 0 /* not a real configuration parameter */
#define CONFIG_MODE 1 /* types of configuration parameters */
#define CONFIG_DISPLAY 2
#define CONFIG_EPSILON 3
#define CONFIG_EPSILONPREC 3 /* not a real type -- tied to CONFIG_EPSILON */
#define CONFIG_TRACE 4
#define CONFIG_MAXPRINT 5
#define CONFIG_MUL2 6
#define CONFIG_SQ2 7
#define CONFIG_POW2 8
#define CONFIG_REDC2 9
#define CONFIG_TILDE 10
#define CONFIG_TAB 11
#define CONFIG_QUOMOD 12
#define CONFIG_QUO 13
#define CONFIG_MOD 14
#define CONFIG_SQRT 15
#define CONFIG_APPR 16
#define CONFIG_CFAPPR 17
#define CONFIG_CFSIM 18
#define CONFIG_OUTROUND 19
#define CONFIG_ROUND 20
#define CONFIG_LEADZERO 21
#define CONFIG_FULLZERO 22
#define CONFIG_MAXERR 23
#define CONFIG_PROMPT 24
#define CONFIG_MORE 25
#define CONFIG_RANDOM 26
/*
* config defult symbols
*/
#define DISPLAY_DEFAULT 20 /* default digits for float display */
#define EPSILON_DEFAULT "1e-20" /* allowed error for float calculations */
#define EPSILONPREC_DEFAULT 67 /* 67 ==> 2^-67 <= EPSILON_DEFAULT < 2^-66 */
#define NEW_EPSILON_DEFAULT "1e-10" /* newstd EPSILON_DEFAULT */
#define NEW_EPSILONPREC_DEFAULT 34 /* 34 ==> 2^-34 <= 1e-10 < 2^-33 */
#define MAXPRINT_DEFAULT 16 /* default number of elements printed */
#define MAXERRORCOUNT 20 /* default max errors before an abort */
/*
* configuration object
*/
struct config {
int outmode; /* current output mode */
long outdigits; /* current output digits for float or exp */
NUMBER *epsilon; /* default error for real functions */
long epsilonprec; /* epsilon binary precision (tied to epsilon) */
FLAG traceflags; /* tracing flags */
long maxprint; /* number of elements to print */
LEN mul2; /* size of number to use multiply algorithm 2 */
LEN sq2; /* size of number to use square algorithm 2 */
LEN pow2; /* size of modulus to use REDC for powers */
LEN redc2; /* size of modulus to use REDC algorithm 2 */
int tilde_ok; /* ok to print a tilde on aproximations */
int tab_ok; /* ok to print tab before numeric values */
long quomod; /* quomod() default rounding mode */
long quo; /* quotent // default rounding mode */
long mod; /* mod % default rounding mode */
long sqrt; /* sqrt() default rounding mode */
long appr; /* appr() default rounding mode */
long cfappr; /* cfappr() default rounding mode */
long cfsim; /* cfsim() default rounding mode */
long outround; /* output default rounding mode */
long round; /* round()/bround() default rounding mode */
int leadzero; /* ok to print leading 0 before decimal pt */
int fullzero; /* ok to print trailing 0's -- XXX ??? */
long maxerrorcount; /* max errors before abort */
char *prompt1; /* normal prompt */
char *prompt2; /* prompt when inside multi-line input */
int random; /* random mode */
};
typedef struct config CONFIG;
/*
* global configuration states and aliases
*/
extern CONFIG *conf; /* current configuration */
extern CONFIG oldstd; /* backward compatible standard configuration */
extern CONFIG newstd; /* new non-backward compatible configuration */
/*
* configuration functions
*/
extern CONFIG *config_copy(CONFIG *src);
extern void config_free(CONFIG *cfg);
extern void config_print(CONFIG *cfg);
extern BOOL config_cmp(CONFIG *cfg1, CONFIG *cfg2);
extern int configtype(char *name);
#endif

113
const.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Constant number storage module.
*/
#include "calc.h"
#define CONSTALLOCSIZE 400 /* number of constants to allocate */
static long constcount; /* number of constants defined */
static long constavail; /* number of constants available */
static NUMBER **consttable; /* table of constants */
/*
* Read in a constant number and add it to the table of constant numbers,
* creating a new entry if necessary. The incoming number is a string
* value which must have a correct format, otherwise an undefined number
* will result. Returns the index of the number in the constant table.
* Returns zero if the number could not be saved.
*
* given:
* str string representation of number
*/
long
addnumber(char *str)
{
NUMBER *q;
q = str2q(str);
if (q == NULL)
return 0;
return addqconstant(q);
}
/*
* Add a particular number to the constant table.
* Returns the index of the number in the constant table, or zero
* if the number could not be saved. The incoming number if freed
* if it is already in the table.
*
* XXX - we should hash the constant table
*
* given:
* q number to be added
*/
long
addqconstant(NUMBER *q)
{
register NUMBER **tp; /* pointer to current number */
register NUMBER *t; /* number being tested */
long index; /* index into constant table */
long numlen; /* numerator length */
long denlen; /* denominator length */
HALF numlow; /* bottom value of numerator */
HALF denlow; /* bottom value of denominator */
numlen = q->num.len;
denlen = q->den.len;
numlow = q->num.v[0];
denlow = q->den.v[0];
tp = &consttable[1];
for (index = 1; index <= constcount; index++) {
t = *tp++;
if ((numlen != t->num.len) || (numlow != t->num.v[0]))
continue;
if ((denlen != t->den.len) || (denlow != t->den.v[0]))
continue;
if (q->num.sign != t->num.sign)
continue;
if (qcmp(q, t) == 0) {
qfree(q);
return index;
}
}
if (constavail <= 0) {
if (consttable == NULL) {
tp = (NUMBER **)
malloc(sizeof(NUMBER *) * (CONSTALLOCSIZE + 1));
*tp = NULL;
} else
tp = (NUMBER **) realloc((char *) consttable,
sizeof(NUMBER *) * (constcount+CONSTALLOCSIZE + 1));
if (tp == NULL)
return 0;
consttable = tp;
constavail = CONSTALLOCSIZE;
}
constavail--;
constcount++;
consttable[constcount] = q;
return constcount;
}
/*
* Return the value of a constant number given its index.
* Returns address of the number, or NULL if the index is illegal.
*/
NUMBER *
constvalue(unsigned long index)
{
if ((index <= 0) || (index > constcount))
return NULL;
return consttable[index];
}
/* END CODE */

78
endian.c Normal file
View File

@@ -0,0 +1,78 @@
/*
* endian - Determine the byte order of a long on your machine.
*
* Big Endian: Amdahl, 68k, Pyramid, Mips, Sparc, ...
* Little Endian: Vax, 32k, Spim (Dec Mips), i386, i486, ...
*/
/*
* Copyright (c) 1993 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#include <stdio.h>
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
/* byte order array */
char byte[8] = { (char)0x12, (char)0x36, (char)0x48, (char)0x59,
(char)0x01, (char)0x23, (char)0x45, (char)0x67 };
MAIN
main(void)
{
/* pointers into the byte order array */
int *intp = (int *)byte;
#if defined(DEBUG)
short *shortp = (short *)byte;
long *longp = (long *)byte;
printf("byte: %02x %02x %02x %02x %02x %02x %02x %02x\n",
byte[0], byte[1], byte[2], byte[3],
byte[4], byte[5], byte[6], byte[7]);
printf("short: %04x %04x %04x %04x\n",
shortp[0], shortp[1], shortp[2], shortp[3]);
printf("int: %08x %08x\n",
intp[0], intp[1]);
printf("long: %08x %08x\n",
longp[0], longp[1]);
#endif
/* Print the standard <machine/endian.h> defines */
printf("#define BIG_ENDIAN\t4321\n");
printf("#define LITTLE_ENDIAN\t1234\n");
/* Determine byte order */
if (intp[0] == 0x12364859) {
/* Most Significant Byte first */
printf("#define BYTE_ORDER\tBIG_ENDIAN\n");
} else if (intp[0] == 0x59483612) {
/* Least Significant Byte first */
printf("#define BYTE_ORDER\tLITTLE_ENDIAN\n");
} else {
fprintf(stderr, "Unknown int Byte Order, set BYTE_ORDER in Makefile\n");
exit(1);
}
exit(0);
}

2308
file.c Normal file

File diff suppressed because it is too large Load Diff

60
file.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 1996 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* File I/O routines callable by users.
*/
#include "have_fpos.h"
/*
* Definition of opened files.
*/
typedef struct {
FILEID id; /* id to identify this file */
FILE *fp; /* real file structure for I/O */
dev_t dev; /* file device */
ino_t inode; /* file inode */
char *name; /* file name */
BOOL reading; /* TRUE if opened for reading */
BOOL writing; /* TRUE if opened for writing */
char action; /* most recent use for 'r', 'w' or 0 */
char mode[3]; /* open mode */
} FILEIO;
/*
* fgetpos/fsetpos vs fseek/ftell interface
*
* f_seek_set(FILE *stream, FILEPOS *loc)
* Seek loc bytes from the beginning of the open file, stream.
*
* f_tell(FILE *stream, FILEPOS *loc)
* Set loc to bytes from the beinning of the open file, stream.
*
* We assume that if your system does not have fgetpos/fsetpos,
* then it will have a FILEPOS that is a scalar type (e.g., long).
* Some obscure systems without fgetpos/fsetpos may not have a simple
* scalar type. In these cases the f_tell macro below will fail.
*/
#if defined(HAVE_FPOS)
#define f_seek_set(stream, loc) fsetpos((FILE*)(stream), (FILEPOS*)(loc))
#define f_tell(stream, loc) fgetpos((FILE*)(stream), (FILEPOS*)(loc))
#else
#define f_seek_set(stream, loc) \
fseek((FILE*)(stream), *(FILEPOS*)(loc), SEEK_SET)
#define f_tell(stream, loc) (*((FILEPOS*)(loc)) = ftell((FILE*)(stream)))
#endif
/*
* external functions
*/
extern int fgetposid(FILEID id, FILEPOS *ptr);
extern int fsetposid(FILEID id, FILEPOS *ptr);

212
fposval.c Normal file
View File

@@ -0,0 +1,212 @@
/*
* fposval - Determine information about the file position type
*
* The include file have_pos.h, as built during the make process will
* define the type FILEPOS as the type used to describe file positions.
* We will print information regarding the size and byte order
* of this definition.
*
* The stat system call returns a stat structure. One of the elements
* of the stat structure is the st_size element. We will print information
* regarding the size and byte order of st_size.
*
* We will #define of 8 symbols:
*
* FILEPOS_BITS length in bits of the type FILEPOS
* SWAP_HALF_IN_FILEPOS will copy/swap FILEPOS into an HALF array
* STSIZE_BITS length in bits of the st_size stat element
* SWAP_HALF_IN_STSIZE will copy/swap st_size into an HALF array
* DEV_BITS length in bits of the st_dev stat element
* SWAP_HALF_IN_DEV will copy/swap st_dev into an HALF array
* INODE_BITS length in bits of the st_ino stat element
* SWAP_HALF_IN_INODE will copy/swap st_ino into an HALF array
*
* With regards to 'will copy/swap ... into an HALF array'. Such macros
* will either be a copy or a copy with HALFs swapped depending on the
* Endian order of the hardware.
*/
/*
* Copyright (c) 1996 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "have_fpos.h"
#include "endian_calc.h"
char *program; /* our name */
MAIN
main(int argc, char **argv)
{
int stsizelen; /* bit length of st_size in buf */
int fileposlen; /* bit length of FILEPOS */
int devlen; /* bit length of st_dev in buf */
int inodelen; /* bit length of st_ino in buf */
struct stat buf; /* file status */
/*
* parse args
*/
program = argv[0];
/*
* print the file position information
*/
fileposlen = sizeof(FILEPOS)*8;
printf("#undef FILEPOS_BITS\n");
printf("#define FILEPOS_BITS %d\n", fileposlen);
#if BYTE_ORDER == BIG_ENDIAN
/*
* Big Endian
*/
if (fileposlen == 64) {
printf("#define SWAP_HALF_IN_FILEPOS(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B64(dest, src)");
} else if (fileposlen == 32) {
printf("#define SWAP_HALF_IN_FILEPOS(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B32(dest, src)");
} else {
fprintf(stderr, "%s: unexpected FILEPOS bit size: %d\n",
program, fileposlen);
exit(1);
}
#else /* BYTE_ORDER == BIG_ENDIAN */
/*
* Little Endian
*
* Normally a "(*(dest) = *(src))" would do, but on some
* systems, a FILEPOS is not a scalar hince we must memcpy.
*/
printf("#define SWAP_HALF_IN_FILEPOS(dest, src)\t%s%d%s\n",
"memcpy((void *)(dest), (void *)(src), sizeof(",fileposlen,"))");
#endif /* BYTE_ORDER == BIG_ENDIAN */
putchar('\n');
/*
* print the stat file size information
*/
stsizelen = sizeof(buf.st_size)*8;
printf("#undef STSIZE_BITS\n");
printf("#define STSIZE_BITS %d\n", stsizelen);
#if BYTE_ORDER == BIG_ENDIAN
/*
* Big Endian
*/
if (stsizelen == 64) {
printf("#define SWAP_HALF_IN_STSIZE(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B64(dest, src)");
} else if (stsizelen == 32) {
printf("#define SWAP_HALF_IN_STSIZE(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B32(dest, src)");
} else {
fprintf(stderr, "%s: unexpected st_size bit size: %d\n",
program, stsizelen);
exit(2);
}
#else /* BYTE_ORDER == BIG_ENDIAN */
/*
* Little Endian
*
* Normally a "(*(dest) = *(src))" would do, but on some
* systems, a STSIZE is not a scalar hince we must memcpy.
*/
printf("#define SWAP_HALF_IN_STSIZE(dest, src)\t%s%d%s\n",
"memcpy((void *)(dest), (void *)(src), sizeof(",stsizelen,"))");
#endif /* BYTE_ORDER == BIG_ENDIAN */
putchar('\n');
/*
* print the dev_t size
*/
devlen = sizeof(buf.st_dev)*8;
printf("#undef DEV_BITS\n");
printf("#define DEV_BITS %d\n", devlen);
#if BYTE_ORDER == BIG_ENDIAN
/*
* Big Endian
*/
if (devlen == 64) {
printf("#define SWAP_HALF_IN_DEV(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B64(dest, src)");
} else if (devlen == 32) {
printf("#define SWAP_HALF_IN_DEV(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B32(dest, src)");
} else if (devlen == 16) {
printf("#define SWAP_HALF_IN_DEV(dest, src)\t\t%s\n",
"(*(dest) = *(src))");
} else {
fprintf(stderr, "%s: unexpected st_dev bit size: %d\n",
program, devlen);
exit(3);
}
#else /* BYTE_ORDER == BIG_ENDIAN */
/*
* Little Endian
*
* Normally a "(*(dest) = *(src))" would do, but on some
* systems, a DEV is not a scalar hince we must memcpy.
*/
printf("#define SWAP_HALF_IN_DEV(dest, src)\t%s%d%s\n",
"memcpy((void *)(dest), (void *)(src), sizeof(",devlen,"))");
#endif /* BYTE_ORDER == BIG_ENDIAN */
putchar('\n');
/*
* print the ino_t size
*/
inodelen = sizeof(buf.st_ino)*8;
printf("#undef INODE_BITS\n");
printf("#define INODE_BITS %d\n", inodelen);
#if BYTE_ORDER == BIG_ENDIAN
/*
* Big Endian
*/
if (inodelen == 64) {
printf("#define SWAP_HALF_IN_INODE(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B64(dest, src)");
} else if (inodelen == 32) {
printf("#define SWAP_HALF_IN_INODE(dest, src)\t\t%s\n",
"SWAP_HALF_IN_B32(dest, src)");
} else if (inodelen == 16) {
printf("#define SWAP_HALF_IN_INODE(dest, src)\t\t%s\n",
"(*(dest) = *(src))");
} else {
fprintf(stderr, "%s: unexpected st_ino bit size: %d\n",
program, inodelen);
exit(4);
}
#else /* BYTE_ORDER == BIG_ENDIAN */
/*
* Little Endian
*
* Normally a "(*(dest) = *(src))" would do, but on some
* systems, a INODE is not a scalar hince we must memcpy.
*/
printf("#define SWAP_HALF_IN_INODE(dest, src)\t%s%d%s\n",
"memcpy((void *)(dest), (void *)(src), sizeof(",inodelen,"))");
#endif /* BYTE_ORDER == BIG_ENDIAN */
exit(0);
}

4819
func.c Normal file

File diff suppressed because it is too large Load Diff

80
func.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*/
#ifndef FUNC_H
#define FUNC_H
#include "calc.h"
#include "label.h"
/*
* Structure of a function.
* The f_opcodes array is actually of variable size.
*/
typedef struct func FUNC;
struct func {
FUNC *f_next; /* next function in list */
unsigned long f_opcodecount; /* size of opcode array */
unsigned int f_localcount; /* number of local variables */
unsigned int f_paramcount; /* max number of parameters */
char *f_name; /* function name */
VALUE f_savedvalue; /* saved value of last expression */
unsigned long f_opcodes[1]; /* array of opcodes (variable length) */
};
/*
* Amount of space needed to allocate a function of n opcodes.
*/
#define funcsize(n) (sizeof(FUNC) + (n) * sizeof(long))
/*
* Size of a character pointer rounded up to a number of opcodes.
*/
#define PTR_SIZE ((sizeof(char *) + sizeof(long) - 1) / sizeof(long))
/*
* The current function being compiled.
*/
extern FUNC *curfunc;
/*
* Functions to handle functions.
*/
extern FUNC *findfunc(long index);
extern char *namefunc(long index);
extern BOOL evaluate(BOOL nestflag);
extern long adduserfunc(char *name);
extern void beginfunc(char *name, BOOL newflag);
extern int builtinopcode(long index);
extern char *builtinname(long index);
extern int dumpop(unsigned long *pc);
extern void addop(long op);
extern void endfunc(void);
extern void addopone(long op, long arg);
extern void addoptwo(long op, long arg1, long arg2);
extern void addoplabel(long op, LABEL *label);
extern void addopptr(long op, char *ptr);
extern void writeindexop(void);
extern void showbuiltins(void);
extern int getbuiltinfunc(char *name);
extern void builtincheck(long index, int count);
extern void addopfunction(long op, long index, int count);
extern void showfunctions(void);
extern void initfunctions(void);
extern void clearopt(void);
extern void updateoldvalue(FUNC *fp);
extern void calculate(FUNC *fp, int argcount);
extern VALUE builtinfunc(long index, int argcount, VALUE *stck);
#endif
/* END CODE */

117
hash.c Normal file
View File

@@ -0,0 +1,117 @@
/* XXX - this code is currently not really used, but it will be soon */
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "value.h"
/*
* hash function interface table
*
* htbl[i] is the interface for hash algorithm i
*/
static HASHFUNC htbl[HASH_TYPE_MAX+1];
/*
* static functions
*/
static void load_htbl(void (*h_func)(HASHFUNC*), HASHFUNC*);
/*
* hash_init - initialize hash function interface table
*
* We will load the hash function interface table and ensure that it is
* completely filled.
*
* This function does not return if an error is encountered.
*/
void
hash_init(void)
{
int i;
/*
* setup
*/
for (i=0; i <= HASH_TYPE_MAX; ++i) {
htbl[i].type = -1;
}
/*
* setup the hash function interface for all hashes
*/
load_htbl(shs_hashfunc, htbl);
/*
* verify that our interface table is fully populated
*/
for (i=0; i <= HASH_TYPE_MAX; ++i) {
if (htbl[i].type != i) {
fprintf(stderr, "htbl[%d] is bad\n", i);
exit(1);
}
}
}
/*
* load_htbl - load a hash function interface table slot
*
* We will call the h_func function, sanity check the function type
* and check to be sure that the slot is unused.
*
* given:
* h_func - a function that returns a HASHFUNC entry
* h - a array of hash function interfaces
*
* This function does not return if an error is encountered.
*/
static void
load_htbl(void (*h_func)(HASHFUNC*), HASHFUNC *h)
{
HASHFUNC hent; /* hash function interface entry */
/*
* call the HASHFUNC interface function
*/
h_func(&hent);
/*
* sanity check the type
*/
if (hent.type < 0 || hent.type > HASH_TYPE_MAX) {
fprintf(stderr, "bad HASHFUNC type: %d\n", hent.type);
exit(1);
}
if (h[hent.type].type >= 0) {
fprintf(stderr, "h[%d].type: %d already in use\n",
hent.type, h[hent.type].type);
exit(1);
}
/*
* load the entry
*/
h[hent.type] = hent;
}

50
hash.h Normal file
View File

@@ -0,0 +1,50 @@
/* XXX - this code is currently not really used, but it will be soon */
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(HASH_H)
#define HASH_H
/*
* hashstate - state of a hash system
*/
struct hashstate {
int type; /* hash type (see XYZ_HASH_TYPE below) */
BOOL prevstr; /* TRUE=>previous value hashed was a string */
union {
SHS_INFO hh_shs; /* old Secure Hash Standard */
} h_union;
};
typedef struct hashstate HASH;
/* For ease in referencing */
#define h_shs h_union.hh_shs
/*
* XYZ_HASH_TYPE - hash types
*
* we support these hash types - must start with 0
*/
#define SHS_HASH_TYPE 0
#define HASH_TYPE_MAX 0 /* must be number of XYZ_HASH_TYPE values */
#endif /* !HASH_H */

58
have_const.c Normal file
View File

@@ -0,0 +1,58 @@
/*
* have_const - Determine if we want or can support ansi const
*
* usage:
* have_const
*
* Not all compilers support const, so this may not compile on your system.
*
* This prog outputs several defines:
*
* HAVE_CONST
* defined ==> ok to use const
* undefined ==> do not use const
*
* CONST
* const ==> use const
* (nothing) ==> const not used
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
MAIN
main(void)
{
#if defined(HAVE_NO_CONST)
printf("#undef HAVE_CONST /* no */\n");
printf("#undef CONST\n");
printf("#define CONST /* no */\n");
#else /* HAVE_NO_CONST */
const char * const str = "const";
printf("#define HAVE_CONST /* yes */\n");
printf("#undef CONST\n");
printf("#define CONST %s /* yes */\n", str);
#endif /* HAVE_NO_CONST */
exit(0);
}

53
have_fpos.c Normal file
View File

@@ -0,0 +1,53 @@
/*
* have_fpos - Determine if have fgetpos and fsetpos functions
*
* If the symbol HAVE_NO_FPOS is defined, we will output nothing.
* If we are able to compile this program, then we must have the
* fgetpos and fsetpos functions and we will output the
* appropriate have_fpos.h file body.
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#include <stdio.h>
MAIN
main(void)
{
#if !defined(HAVE_NO_FPOS)
fpos_t pos; /* file position */
/* get the current position */
(void) fgetpos(stdin, &pos);
/* set the current position */
(void) fsetpos(stdin, &pos);
/* print a have_fpos.h body that says we have the functions */
printf("#undef HAVE_FPOS\n");
printf("#define HAVE_FPOS 1 /* yes */\n\n");
printf("typedef fpos_t FILEPOS;\n");
#endif
exit(0);
}

60
have_newstr.c Normal file
View File

@@ -0,0 +1,60 @@
/*
* have_newstr - Determine if we have a system without ANSI C string functions
*
* usage:
* have_newstr
*
* Not all systems support all ANSI C string functions, so this may not
* compile on your system.
*
* This prog outputs several defines:
*
* HAVE_NEWSTR
* defined ==> use memcpy(), memset(), strchr()
* undefined ==> use bcopy() instead of memcpy(),
* use bfill() instead of memset(),
* use index() instead of strchr()
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#define MOVELEN 3
char src[] = "chongo was here";
char dest[MOVELEN+1];
MAIN
main(void)
{
#if defined(HAVE_NO_NEWSTR)
printf("#undef HAVE_NEWSTR /* no */\n");
#else /* HAVE_NO_NEWSTR */
(void) memcpy(dest, src, MOVELEN);
(void) memset(dest, 0, MOVELEN);
(void) strchr(src, 'e');
printf("#define HAVE_NEWSTR /* yes */\n");
#endif /* HAVE_NO_NEWSTR */
exit(0);
}

139
have_stdvs.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* have_stdvs - try <stdarg.h> to see if it really works with vsprintf()
*
* On some systems that have both <stdarg.h> and <varargs.h>, vsprintf()
* does not work well under one type of include file.
*
* Some systems (such as UMIPS) have bugs in the <stdarg.h> implementation
* that show up in vsprintf(), so we may have to try to use sprintf()
* as if it were vsprintf() and hope for the best.
*
* This program will output #defines and exits 0 if vsprintf() (or sprintf())
* produces the results that we expect. This program exits 1 if vsprintf()
* (or sprintf()) produces unexpected results while using the <stdarg.h>
* include file.
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#include <stdio.h>
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include <stdarg.h>
#include "have_string.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
char buf[BUFSIZ];
void
try(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
#if !defined(DONT_HAVE_VSPRINTF)
vsprintf(buf, fmt, ap);
#else
sprintf(buf, fmt, ap);
#endif
va_end(ap);
}
MAIN
main(void)
{
/*
* setup
*/
buf[0] = '\0';
/*
* test variable args and vsprintf/sprintf
*/
try("@%d:%s:%d@", 1, "hi", 2);
if (strcmp(buf, "@1:hi:2@") != 0) {
#if !defined(DONT_HAVE_VSPRINTF)
/* <stdarg.h> with vsprintf() didn't work */
#else
/* <stdarg.h> with sprintf() simulating vsprintf() didn't work */
#endif
exit(1);
}
try("%s %d%s%d%d %s",
"Landon Noll 1st proved that", 2, "^", 23209, -1, "was prime");
if (strcmp(buf, "Landon Noll 1st proved that 2^23209-1 was prime") != 0) {
#if !defined(DONT_HAVE_VSPRINTF)
/* <stdarg.h> with vsprintf() didn't work */
#else
/* <stdarg.h> with sprintf() simulating vsprintf() didn't work */
#endif
exit(1);
}
/*
* report the result
*/
puts("/* what type of variable args do we have? */");
#if defined(DONT_HAVE_VSPRINTF)
puts("/*");
puts(" * SIMULATE_STDARG");
puts(" *");
puts(" * WARNING: This type of stdarg makes assumptions about the stack");
puts(" * that may not be true on your system. You may want to");
puts(" * define STDARG (if using ANSI C) or VARARGS.");
puts(" */");
puts("typedef char *va_list;");
puts("#define va_start(ap,parmn) (void)((ap) = (char*)(&(parmn) + 1))");
puts("#define va_end(ap) (void)((ap) = 0)");
puts("#define va_arg(ap, type) \\");
puts(" (((type*)((ap) = ((ap) + sizeof(type))))[-1])");
puts("#define SIMULATE_STDARG /* use std_arg.h to simulate <stdarg.h> */");
#else
puts("#define STDARG /* use <stdarg.h> */");
puts("#include <stdarg.h>");
#endif
puts("\n/* should we use vsprintf()? */");
#if !defined(DONT_HAVE_VSPRINTF)
puts("#define HAVE_VS /* yes */");
#else
puts("/*");
puts(" * Hack aleart!!!");
puts(" *");
puts(" * Systems that do not have vsprintf() need something. In some");
puts(" * cases the sprintf function will deal correctly with the");
puts(" * va_alist 3rd arg. Hope for the best!");
puts(" */");
puts("#define vsprintf sprintf");
puts("#undef HAVE_VS");
#endif
exit(0);
}

62
have_uid_t.c Normal file
View File

@@ -0,0 +1,62 @@
/*
* have_uid_t - Determine if we want or can support uid_t
*
* usage:
* have_uid_t
*
* Not all compilers support uid_t, so this may not compile on your system.
*
* This prog outputs several defines:
*
* HAVE_UID_T
* defined ==> ok to use uid_t
* undefined ==> do not use uid_t
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#if !defined(HAVE_NO_UID_T)
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include <pwd.h>
#include <sys/types.h>
#endif /* ! HAVE_NO_UID_T */
MAIN
main(void)
{
#if defined(HAVE_NO_UID_T)
printf("#undef HAVE_UID_T /* no */\n");
#else /* HAVE_NO_UID_T */
uid_t curds;
extern uid_t geteuid();
curds = geteuid();
printf("#define HAVE_UID_T /* yes */\n");
#endif /* HAVE_NO_UID_T */
exit(0);
}

131
have_varvs.c Normal file
View File

@@ -0,0 +1,131 @@
/*
* have_varvs - try <varargs.h> to see if it really works with vsprintf()
*
* Some systems have bugs in the <varargs.h> implementation that show up in
* vsprintf(), so we may have to try to use sprintf() as if it were vsprintf()
* and hope for the best.
*
* This program will output #defines and exits 0 if vsprintf() (or sprintf())
* produces the results that we expect. This program exits 1 if vsprintf()
* (or sprintf()) produces unexpected results while using the <stdarg.h>
* include file.
*/
/*
* Copyright (c) 1995 by Landon Curt Noll. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright, this permission notice and text
* this comment, and the disclaimer below appear in all of the following:
*
* supporting documentation
* source copies
* source works derived from this source
* binaries derived from this source or from derived source
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* chongo was here /\../\
*/
#include <stdio.h>
#include "have_unistd.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include "have_string.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
char buf[BUFSIZ];
#if !defined(STDARG) && !defined(SIMULATE_STDARG)
#include <varargs.h>
void
try(char *fmt, ...)
{
va_list ap;
va_start(ap);
#if !defined(DONT_HAVE_VSPRINTF)
vsprintf(buf, fmt, ap);
#else
sprintf(buf, fmt, ap);
#endif
va_end(ap);
}
#else
void
try(char *a, int b, char *c, int d)
{
return;
}
#endif
MAIN
main(void)
{
/*
* setup
*/
buf[0] = '\0';
/*
* test variable args and vsprintf/sprintf
*/
try("@%d:%s:%d@", 1, "hi", 2);
if (strcmp(buf, "@1:hi:2@") != 0) {
#if !defined(DONT_HAVE_VSPRINTF)
/* <varargs.h> with vsprintf() didn't work */
#else
/* <varargs.h> with sprintf() simulating vsprintf() didn't work */
#endif
exit(1);
}
try("%s %d%s%d%d %s",
"Landon Noll 1st proved that", 2, "^", 23209, -1, "was prime");
if (strcmp(buf, "Landon Noll 1st proved that 2^23209-1 was prime") != 0) {
#if !defined(DONT_HAVE_VSPRINTF)
/* <stdarg.h> with vsprintf() didn't work */
#else
/* <stdarg.h> with sprintf() simulating vsprintf() didn't work */
#endif
exit(1);
}
/*
* report the result
*/
puts("/* what type of variable args do we have? */");
puts("#define VARARGS /* use <varargs.h> */");
puts("#include <varargs.h>");
puts("\n/* should we use vsprintf()? */");
#if !defined(DONT_HAVE_VSPRINTF)
puts("#define HAVE_VS /* yes */");
#else
puts("/*");
puts(" * Hack aleart!!!");
puts(" *");
puts(" * Systems that do not have vsprintf() need something. In some");
puts(" * cases the sprintf function will deal correctly with the");
puts(" * va_alist 3rd arg. Hope for the best!");
puts(" */");
puts("#define vsprintf sprintf");
puts("#undef HAVE_VS");
#endif
exit(0);
}

369
help/Makefile Normal file
View File

@@ -0,0 +1,369 @@
#
# help - makefile for calc help files
#
# Copyright (c) 1994 David I. Bell and Landon Curt Noll
# Permission is granted to use, distribute, or modify this source,
# provided that this copyright notice remains intact.
#
# Arbitrary precision calculator.
#
# calculator by David I. Bell
# makefile by Landon Curt Noll
# required vars
#
SHELL= /bin/sh
MAKE_FILE = Makefile
# Normally, the upper level makefile will set these values. We provide
# a default here just in case you want to build from this directory.
#
TOPDIR= /usr/local/lib
#TOPDIR= /usr/lib
#TOPDIR= /usr/libdata
LIBDIR= ${TOPDIR}/calc
HELPDIR= ${LIBDIR}/help
# Makefile debug
#
# Q=@ do not echo internal makefile actions (quiet mode)
# Q= echo internal makefile actions (debug / verbose mode)
#
#Q=
Q=@
# standard tools
#
NATIVE_CC= cc
NATIVE_CFLAGS=
SED= sed
SORT= sort
FMT= fmt
CMP= cmp
CAT= cat
# Standard help files
#
# The obj.file is special and is not listed here.
#
STD_HELP_FILES1= intro overview help command config \
define environment expression file history interrupt mat
STD_HELP_FILES2= operator statement types usage variable
STD_HELP_FILES3= todo credit
STD_HELP_FILES= ${STD_HELP_FILES1} ${STD_HELP_FILES2} ${STD_HELP_FILES3}
SYMBOL_HELP= assign
# These two lists are prodiced by the detaillist and missinglist rules
# when no WARNINGS are detected.
#
DETAIL_HELP= abs access acos acosh acot acoth acsc acsch append appr archive \
arg asec asech asin asinh assoc atan atan2 atanh avg base bround \
btrunc ceil cfappr cfsim char cmdbuf cmp comb conj cos cosh cot coth \
count cp csc csch ctime delete den det digit digits dp epsilon errno \
error eval exp fact factor fclose fcnt feof ferror fflush fgetc \
fgetfield fgetline fgets fgetstr fib files floor fopen forall fprintf \
fputc fputs fputstr frac frem freopen fscan fscanf fseek fsize ftell \
gcd gcdrem getenv hash head highbit hmean hypot ilog ilog10 ilog2 im \
insert int inverse iroot isassoc isatty isconfig iserror iseven \
isfile ishash isident isint islist ismat ismult isnull isnum isobj \
isodd isprime isqrt isrand israndom isreal isrel isset issimple issq \
isstr istype jacobi join lcm lcmfact lfactor list ln lowbit ltol \
makelist matdim matfill matmax matmin matsum mattrans max meq min \
minv mmin mne mod modify near newerror nextcand nextprime norm null \
num ord param perm pfact pi pix places pmod polar poly pop power \
prevcand prevprime printf prompt ptest push putenv quo quomod rand \
randbit randperm rcin rcmul rcout rcpow rcsq re rm remove reverse \
rewind root round rsearch runtime scale scan scanf search sec sech \
segment select sgn sin sinh size sizeof sort sqrt srand ssq str \
strcat strerror strlen strpos strprintf strscan strscanf substr swap \
system tail tan tanh time trunc xor
# Help files that are constructed from other sources
#
# The obj.file is special and is not listed here.
#
BUILT_HELP_FILES= bindings altbind changes libcalc stdlib bugs errorcodes
# Singular files
#
# These files are copies of their plural form.
#
PLURAL_FILES= bindings bugs changes errorcodes types
SINGULAR_FILES= binding bug change errorcode type
# These files are found (but not built) in the distribution
#
DISTLIST= ${STD_HELP_FILES} ${DETAIL_HELP} ${SYMBOL_HELP} ${MAKE_FILE} \
obj.file builtin.top builtin.end funclist.sed \
errorcodes.hdr errorcodes.sed
all: ${STD_HELP_FILES} obj.file ${BUILT_HELP_FILES} full \
${DETAIL_HELP} ${SINGULAR_FILES} builtin .all
# used by the upper level Makefile to determine of we have done all
#
# NOTE: Due to bogus shells found on one common system we must have
# an non-emoty else clause for every if condition. *sigh*
#
.all:
rm -f .all
touch .all
bindings: ../lib/bindings
rm -f bindings
cp ../lib/bindings bindings
chmod 0444 bindings
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
altbind: ../lib/altbind
rm -f altbind
cp ../lib/altbind altbind
chmod 0444 altbind
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
stdlib: ../lib/README
rm -f stdlib
cp ../lib/README stdlib
chmod 0444 stdlib
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
changes: ../CHANGES
rm -f changes
cp ../CHANGES changes
chmod 0444 changes
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
libcalc: ../LIBRARY
rm -f libcalc
${SED} -e 's:$${LIBDIR}:${LIBDIR}:g' < ../LIBRARY > libcalc
chmod 0444 libcalc
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
bugs: ../BUGS
rm -f bugs
cp ../BUGS bugs
chmod 0444 bugs
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
errorcodes: ../calcerr.h errorcodes.hdr errorcodes.sed
rm -f errorcodes
${CAT} errorcodes.hdr > errorcodes
${SED} -n -f errorcodes.sed < ../calcerr.h >> errorcodes
chmod 0444 errorcodes
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
full: ${STD_HELP_FILES} ${BUILT_HELP_FILES} ${MAKE_FILE}
${Q}echo "forming full"
-${Q}rm -f full
-${Q}for i in ${STD_HELP_FILES1} obj.file ${STD_HELP_FILES2} \
${BUILT_HELP_FILES} ${STD_HELP_FILES3}; do \
if [ Xintro != X"$$i" ]; then \
echo " "; \
else \
true; \
fi; \
if [ Xobj.file = X"$$i" ]; then \
j=obj; \
else \
j=$$i; \
fi; \
echo "*************"; \
echo "* $$j"; \
echo "*************"; \
echo ""; \
cat $$i; \
done > full
${Q}echo "full formed"
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
# Singular files are the same files as their plural form.
#
${SINGULAR_FILES}: ${PLURAL_FILES}
${Q}for i in ${SINGULAR_FILES}; do \
echo "rm -f $${i}"; \
rm -f $${i}; \
echo "cp $${i}s $${i}"; \
cp $${i}s $${i}; \
done
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/SINGULAR_FILES =-=-='; \
echo ''; \
else \
true; \
fi
# Form the builtin file
#
# We ave a "chicken-and-egg" problem. We want the builtn help file to
# accurately reflect the function list. It would be nice if we could
# just execute calc show builtin, but calc may not have been built or
# buildable at this point. The hack-a-round used is to convert ../func.c
# into a standalone program that generates a suitable function list
# that is standwiched between the top and bottom builtin help text.
#
# We form funclist.c by sedding out unwanted stuff from builtins table,
# converting NUMBER* and VALUE into harmless types and converting
# the showbuiltins() function into main(). Combined with the -DFUNCLIST
# we will avoid all of the complex calc types, macros and defines and
# be left with just main() and a mininal builtins table.
#
# Building funclist.o a portable fashion is ugly because some systems
# do not treat -I.. correctly!
#
builtin: builtin.top builtin.end ../func.c funclist.sed
${Q}echo "forming builtin help file"
-${Q}rm -f builtin
${Q}cat builtin.top > builtin
-${Q}rm -f funclist.c
${Q}${SED} -n -f funclist.sed ../func.c > funclist.c
-${Q}rm -f ../funclist.c ../funclist.o ../funclist funclist
${Q}cp funclist.c ..
-${Q}(cd ..; \
${NATIVE_CC} ${NATIVE_CFLAGS} -DFUNCLIST funclist.c -o funclist; \
mv funclist help; \
rm -f funclist.c funclist.o funclist)
${Q}./funclist | \
${SED} -e 's/^/ /' -e 's/[ ][ ]*$$//' >> builtin
${Q}cat builtin.end >> builtin
${Q}echo "builtin help file formed"
-@if [ -z "${Q}" ]; then \
echo ''; \
echo '=-=-= skipping the cat of help/$@ =-=-='; \
echo ''; \
else \
true; \
fi
##
#
# File list generation. You can ignore this section.
#
#
# We will form the names of source files as if they were in a
# sub-directory called calc/help.
#
##
distlist: ${DISTLIST}
${Q}for i in ${DISTLIST}; do \
echo calc/help/$$i; \
done | ${SORT}
# The bsdi distribution has generated files as well as distributed files.
#
bsdilist: ${DISTLIST} ${BUILT_HELP_FILES}
${Q}for i in ${DISTLIST} ${BUILT_HELP_FILES}; do \
echo calc/help/$$i; \
done | ${SORT}
# The BSDI cdrom makefile expects all help files to be pre-built. This rule
# creats these fils so that the release can be shipped off to BSDI. You can
# ignore this rule.
#
bsdi: all
rm -f obj
cp obj.file obj
# These next rule help me form the ${DETAIL_HELP} makefile variables above.
#
detaillist:
${Q}-(echo "xxxxx"; \
for i in ${DETAIL_HELP}; do \
if [ ! -f SCCS/s.$$i ]; then \
echo "WARNING: $$i not under SCCS control" 1>&2; \
else \
echo $$i; \
fi; \
done | ${SORT}) | ${FMT} -70 | \
${SED} -e '1s/xxxxx/DETAIL_HELP=/' -e '2,$$s/^/ /' \
-e 's/$$/ \\/' -e '$$s/ \\$$//'
clean:
rm -f obj mkbuiltin funclist.c funclist.o funclist
clobber:
rm -f ${BUILT_HELP_FILES} full builtin .all
rm -f obj mkbuiltin funclist.c funclist.o funclist ${SINGULAR_FILES}
install: all
-${Q}if [ ! -d ${TOPDIR} ]; then \
echo mkdir ${TOPDIR}; \
mkdir ${TOPDIR}; \
else \
true; \
fi
-${Q}if [ ! -d ${LIBDIR} ]; then \
echo mkdir ${LIBDIR}; \
mkdir ${LIBDIR}; \
else \
true; \
fi
-${Q}if [ ! -d ${HELPDIR} ]; then \
echo mkdir ${HELPDIR}; \
mkdir ${HELPDIR}; \
else \
true; \
fi
${Q}for i in ${STD_HELP_FILES} ${BUILT_HELP_FILES} builtin \
full ${DETAIL_HELP} ${SINGULAR_FILES} ${SYMBOL_HELP}; do \
echo rm -f ${HELPDIR}/$$i; \
rm -f ${HELPDIR}/$$i; \
echo cp $$i ${HELPDIR}; \
cp $$i ${HELPDIR}; \
echo chmod 0444 ${HELPDIR}/$$i; \
chmod 0444 ${HELPDIR}/$$i; \
done
rm -f ${HELPDIR}/obj
cp obj.file ${HELPDIR}/obj
chmod 0444 ${HELPDIR}/obj

41
help/abs Normal file
View File

@@ -0,0 +1,41 @@
NAME
abs - absolute value
SYNOPSIS
abs(x [,eps])
TYPES
If x is an object of type xx, the function xx_abs has to have
been defined; this will determine the types for x, eps and
the returned value.
For non-object x and eps:
x number (real or complex)
eps ignored if x is real, nonzero real for complex x,
defaults to epsilon().
return real
DESCRIPTION
If x is real, returns x if x is positive or zero, -x if x is negative.
For complex x, returns the multiple of eps nearest or next to nearest
to the absolute value of x. The result usually has error less in
absolute value than abs(eps), but should not exceed 0.75 * abs(eps).
EXAMPLE
> print abs(3.4), abs(-3.4)
3.4 3.4
> print abs(3+4i, 1e-5), abs(4+5i, 1e-5), abs(4+5i, 1e-10)
5 6.40312 6.4031242374
LIMITS
none
LIBRARY
none
SEE ALSO
cmp, epsilon, hypot, norm, near, obj

46
help/access Normal file
View File

@@ -0,0 +1,46 @@
NAME
access - determine existence or accessibility of named file
SYNOPSIS
access(name [, mode])
TYPES
name string
mode integer or string containing only 'r', 'w', 'x' characters
return null value or error
DESCRIPTION
access(name) or access(name, 0) or access(name, "") returns the null
value if a file with this name exists.
If non-null mode is specified, the null value is returned if there
is a file with the specified name and accessibility indicated by the
bits or characters of the mode argument: 'r' or bit 2 for reading,
'w' or bit 1 for writing, 'x' or bit 0 for execution.
EXAMPLE
> !rm -f junk
> access("junk")
Error 10002 XXX This number will probably be changed
> f = fopen("junk", "w")
> access("junk")
> fputs(f, "Now is the time");
> freopen(f, "r");
> !chmod u-w junk
> fgets(f)
"Now is the time"
> access("junk", "w")
Error 10013 XXX
> freopen(f, "w")
Error 10013 XXX
LIMITS
none - XXX - is this correct?
LIBRARY
none - XXX - is this correct?
SEE ALSO
errno, fclose, feof, ferror, fflush, fgetc, fgetline, fgets, files, fopen,
fprintf, fputc, fputs, fseek, fsize, ftell, isfile, printf, prompt

32
help/acos Normal file
View File

@@ -0,0 +1,32 @@
NAME
acos - inverse trigonometric cosine
SYNOPSIS
acos(x [,eps])
TYPES
x real, -1 <= x <= 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the acos of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = acos(x) is the number in [0, pi] for which cos(v) = x.
EXAMPLE
> print acos(.5, 1e-5), acos(.5, 1e-10), acos(.5, 1e-15), acos(.5, 1e-20)
1.0472 1.0471975512 1.047197551196598 1.04719755119659774615
LIMITS
unlike sin and cos, x must be real
abs(x) <= 1
eps > 0
LIBRARY
NUMBER *qacos(NUMBER *x, NUMBER *eps)
SEE ALSO
asin, atan, asec, acsc, acot, epsilon

32
help/acosh Normal file
View File

@@ -0,0 +1,32 @@
NAME
acosh - inverse hyperbolic cosine
SYNOPSIS
acosh(x [,eps])
TYPES
x real, x >= 1
eps nonzero real, defaults to epsilon()
return nonnegative real
DESCRIPTION
Returns the cosh of x to a multiple of eps with error less in
absolute value than .75 * eps.
acosh(x) = ln(x + sqrt(x^2 - 1)) is the nonnegative real number v
for which cosh(v) = x.
EXAMPLE
> print acosh(2, 1e-5), acosh(2, 1e-10), acosh(2, 1e-15), acosh(2, 1e-20)
1.31696 1.3169578969 1.316957896924817 1.31695789692481670862
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qacosh(NUMBER *x, NUMBER *eps)
SEE ALSO
asinh, atanh, asech, acsch, acoth, epsilon

31
help/acot Normal file
View File

@@ -0,0 +1,31 @@
NAME
acot - inverse trigonometric cotangent
SYNOPSIS
acot(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the acot of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = acot(x) is the number in (0, pi) for which cot(v) = x.
EXAMPLE
> print acot(2, 1e-5), acot(2, 1e-10), acot(2, 1e-15), acot(2, 1e-20)
.46365 .463647609 .463647609000806 .46364760900080611621
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qacot(NUMBER *x, NUMBER *eps)
SEE ALSO
asin, acos, atan, asec, acsc, epsilon

33
help/acoth Normal file
View File

@@ -0,0 +1,33 @@
NAME
acoth - inverse hyperbolic cotangent
SYNOPSIS
acoth(x [,eps])
TYPES
x real, with abs(x) > 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the acoth of x to a multiple of eps with error less in
absolute value than .75 * eps.
acoth(x) = ln((x + 1)/(x - 1))/2 is the real number v for which
coth(v) = x.
EXAMPLE
> print acoth(2, 1e-5), acoth(2, 1e-10), acoth(2, 1e-15), acoth(2, 1e-20)
.54931 .5493061443 .549306144334055 .5493061443340548457
LIMITS
unlike sin and cos, x must be real
abs(x) > 1
eps > 0
LIBRARY
NUMBER *qacoth(NUMBER *x, NUMBER *eps)
SEE ALSO
asinh, acosh, atanh, asech, acsch, epsilon

32
help/acsc Normal file
View File

@@ -0,0 +1,32 @@
NAME
acsc - inverse trigonometric cosecant
SYNOPSIS
acsc(x [,eps])
TYPES
x real, with absolute value >= 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the acsc of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = acsc(x) is the number in [-pi/2, pi/2] for which csc(v) = x.
EXAMPLE
> print acsc(2, 1e-5), acsc(2, 1e-10), acsc(2, 1e-15), acsc(2, 1e-20)
.5236 .5235987756 .523598775598299 .52359877559829887308
LIMITS
unlike sin and cos, x must be real
abs(x) >= 1
eps > 0
LIBRARY
NUMBER *qacsc(NUMBER *x, NUMBER *eps)
SEE ALSO
asin, acos, atan, asec, acot, epsilon

33
help/acsch Normal file
View File

@@ -0,0 +1,33 @@
NAME
acsch - inverse hyperbolic cosecant
SYNOPSIS
acsch(x [,eps])
TYPES
x nonzero real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the acsch of x to a multiple of eps with error less in
absolute value than .75 * eps.
acsch(x) = ln((1 + sqrt(1 + x^2))/x) is the real number v for
which csch(v) = x.
EXAMPLE
> print acsch(2, 1e-5), acsch(2, 1e-10), acsch(2, 1e-15), acsch(2, 1e-20)
.48121 .4812118251 .481211825059603 .4812118250596034475
LIMITS
unlike sin and cos, x must be real
x != 0
eps > 0
LIBRARY
NUMBER *qacsch(NUMBER *x, NUMBER *eps)
SEE ALSO
asinh, acosh, atanh, asech, acoth, epsilon

60
help/append Normal file
View File

@@ -0,0 +1,60 @@
NAME
append - append one or more values to end of list
SYNOPSIS
append(x, y_0, y_1, ...)
TYPES
x lvalue whose value is a list
y_0, ... any
return null value
DESCRIPTION
If after evaluation of y_0, y_1, ..., x is a list with contents
(x_0, x_1, ...), then after append(x, y_0, y_1, ...), x has
contents (x_0, x_1, ..., y_0, y_1, ...).
If after evaluation of y_0, y_1, ..., x has size n,
append(x, y_0, y_1, ...) is equivalent to insert(x, n, y_0, y_1, ...).
EXAMPLE
> x = list(2,3,4)
> append(x, 5, 6)
> print x
list (5 elements, 5 nonzero):
[[0]] = 2
[[1]] = 3
[[2]] = 4
[[3]] = 5
[[4]] = 6
> append(x, pop(x), pop(x))
> print x
list (5 elements, 5 nonzero):
[[0]] = 4
[[1]] = 5
[[2]] = 6
[[3]] = 2
[[4]] = 3
> append(x, (remove(x), 7))
> print x
list (5 elements, 5 nonzero):
[[0]] = 4
[[1]] = 5
[[2]] = 6
[[3]] = 2
[[4]] = 7
LIMITS
append() can have at most 100 arguments
LIBRARY
none
SEE ALSO
delete, insert, islist, list, pop, push, remove, rsearch, search, size

146
help/appr Normal file
View File

@@ -0,0 +1,146 @@
NAME
appr - approximate numbers by multiples of a specified number
SYNOPSIS
appr(x [,y [,z]])
TYPES
x real, complex, matrix, list
y real
z integer
return same type as x except that complex x may return a real number
DESCRIPTION
Return the approximate value of x as specified by a specific error
(epsilon) and config ("appr") value.
The default value for y is epsilon(). The default value for z is
the current value of the "appr" configuration parameter.
If y is zero or x is a multiple of y, appr(x,y,z) returns x. I.e.,
there is no "approximation" - the result represents x exactly.
In the following it is assumed y is nonzero and x is not a multiple of y.
For Real x:
appr(x,y,z) is either the nearest multiple of y greater
than x or the nearest multiple of y less than x. Thus, if
we write a = appr(x,y,z) and r = x - a, then a/y is an integer
and abs(r) < abs(y). If r > 0, we say x has been "rounded down"
to a; if r < 0, the rounding is "up". For particular x and y,
whether the rounding is down or up is determined by z.
Only the 5 lowest bits of z are used, so we may assume z has been
replaced by its value modulo 32. The type of rounding depends on
z as follows:
z = 0 round down or up according as y is positive or negative,
sgn(r) = sgn(y)
z = 1 round up or down according as y is positive or negative,
sgn(r) = -sgn(y)
z = 2 round towards zero, sgn(r) = sgn(x)
z = 3 round away from zero, sgn(r) = -sgn(x)
z = 4 round down
z = 5 round up
z = 6 round towards or from zero according as y is positive or
negative, sgn(r) = sgn(x/y)
z = 7 round from or towards zero according as y is positive or
negative, sgn(r) = -sgn(x/y)
z = 8 a/y is even
z = 9 a/y is odd
z = 10 a/y is even or odd according as x/y is positive or negative
z = 11 a/y is odd or even according as x/y is positive or negative
z = 12 a/y is even or odd according as y is positive or negative
z = 13 a/y is odd or even according as y is positive or negative
z = 14 a/y is even or odd according as x is positive or negative
z = 15 a/y is odd or even according as x is positive or negative
z = 16 to 31 abs(r) <= abs(y)/2; if there is a unique multiple
of y that is nearest x, appr(x,y,z) is that multiple of y
and then abs(r) < abs(y)/2. If x is midway between
successive multiples of y, then abs(r) = abs(y)/2 and
the value of a is as given by appr(x, y, z-16).
Matrix or List x:
appr(x,y,z) returns the matrix or list indexed in the same way as x,
in which each element t has been replaced by appr(t,y,z).
XXX - complex x needs to be documented
PROPERTIES
If appr(x,y,z) != x, then abs(x - appr(x,y,z)) < abs(y).
If appr(x,y,z) != x and 16 <= z <= 31, abs(x - appr(x,y,z)) <= abs(y)/2.
For z = 0, 1, 4, 5, 16, 17, 20 or 21, and any integer n,
appr(x + n*y, y, z) = appr(x, y, z) + n * y.
If y is nonzero, appr(x,y,8)/y = an odd integer n only if x = n * y.
EXAMPLES
> print appr(-5.44,0.1,0), appr(5.44,0.1,0), appr(5.7,1,0), appr(-5.7,1,0)
-5.5 5.4 5 -6
> print appr(-5.44,-.1,0), appr(5.44,-.1,0), appr(5.7,-1,0), appr(-5.7,-1,0)
-5.4 5.5 6 -5
> print appr(-5.44,0.1,3), appr(5.44,0.1,3), appr(5.7,1,3), appr(-5.7,1,3)
-5.5 5.5 6 -6
> print appr(-5.44,0.1,4), appr(5.44,0.1,4), appr(5.7,1,4), appr(-5.7,1,4)
-5.5 5.4 5 -6
> print appr(-5.44,0.1,6), appr(5.44,0.1,6), appr(5.7,1,6), appr(-5.7,1,6)
-5.4 5.4 6 -5
> print appr(-5.44,-.1,6), appr(5.44,-.1,6), appr(5.7,-1,6), appr(-5.7,-1,6)
-5.5 5.5 6 -6
> print appr(-5.44,0.1,9), appr(5.44,0.1,9), appr(5.7,1,9), appr(-5.7,1,9)
-5.5 5.5 5 -5
> print appr(-.44,0.1,11), appr(.44,0.1,11), appr(5.7,1,11), appr(-5.7,1,11)
-.4 .5 5 -6
> print appr(-.44,-.1,11),appr(.44,-.1,11),appr(5.7,-1,11),appr(-5.7,-1,11)
-.5 .4 6 -5
> print appr(-.44,0.1,12), appr(.44,0.1,12), appr(5.7,1,12), appr(-5.7,1,12)
-.4 .5 5 -6
> print appr(-.44,-.1,12),appr(.44,-.1,12),appr(5.7,-1,12),appr(-5.7,-1,12)
-.5 .4 6 -5
> print appr(-.44,0.1,15), appr(.44,0.1,15), appr(5.7,1,15), appr(-5.7,1,15)
-.4 .5 5 -6
> print appr(-.44,-.1,15),appr(.44,-.1,15),appr(5.7,-1,15),appr(-5.7,-1,15)
-.4 .5 5 -6
LIMITS
none
LIBRARY
NUMBER *qmappr(NUMBER *q, NUMBER *e, long R);
LIST *listappr(LIST *oldlp, VALUE *v2, VALUE *v3);
MATRIX *matappr(MATRIX *m, VALUE *v2, VALUE *v3);
SEE ALSO
round, bround, cfappr, cfsim

25
help/archive Normal file
View File

@@ -0,0 +1,25 @@
Where to get the the latest versions of calc
Landon Noll maintains the official calc ftp archive at:
ftp://ftp.uu.net/pub/calc
Alpha test versions, complete with bugs, untested code and
experimental features may be fetched (if you are brave) under:
http://reality.sgi.com/chongo/calc/
One may join the calc testing group by sending a request to:
calc-tester-request@postofc.corp.sgi.com
Your message body (not the subject) should consist of:
subscribe calc-tester address
end
name your_full_name
where "address" is your EMail address and "your_full_name"
is your full name.
Landon Curt Noll <chongo@toad.com> /\oo/\

33
help/arg Normal file
View File

@@ -0,0 +1,33 @@
NAME
arg - argument (the angle or phase) of a complex number
SYNOPSIS
arg(x [,eps])
TYPES
x number
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the argument of x to the nearest or next to nearest multiple of
eps; the error will be less in absolute value than 0.75 * abs(eps),
but usually less than 0.5 * abs(eps). By default, acc is epsilon().
EXAMPLE
> print arg(2), arg(2+3i, 1e-5), arg(2+3i, 1e-10), arg(2+3i, 1e-20)
0 .98279 .9827937232 .98279372324732906799
> pi = pi(1e-10); deg = pi/180; eps = deg/10000
> print arg(2+3i, eps)/deg, arg(-1 +1i, eps)/deg, arg(-1 - 1i,eps)/deg
56.3099 135 -135
LIMITS
none
LIBRARY
none
SEE ALSO
conj, im, polar, re

32
help/asec Normal file
View File

@@ -0,0 +1,32 @@
NAME
asec - inverse trigonometric secant
SYNOPSIS
asec(x [,eps])
TYPES
x real, with absolute value >= 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the asec of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = asec(x) is the number in [0, pi] for which sec(v) = x.
EXAMPLE
> print asec(2, 1e-5), asec(2, 1e-10), asec(2, 1e-15), asec(2, 1e-20)
1.0472 1.0471975512 1.047197551196598 1.04719755119659774615
LIMITS
unlike sin and cos, x must be real
abs(x) >= 1
eps > 0
LIBRARY
NUMBER *qasec(NUMBER *x, NUMBER *eps)
SEE ALSO
asin, acos, atan, acsc, acot, epsilon

33
help/asech Normal file
View File

@@ -0,0 +1,33 @@
NAME
asech - inverse hyperbolic secant
SYNOPSIS
asech(x [,eps])
TYPES
x real, 0 < x <= 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the asech of x to a multiple of eps with error less in
absolute value than .75 * eps.
asech(x) = ln((1 + sqrt(1 - x^2))/x) is the real number v for which
sech(v) = x.
EXAMPLE
> print asech(.5,1e-5), asech(.5,1e-10), asech(.5,1e-15), asech(.5,1e-20)
1.31696 1.3169578969 1.316957896924817 1.31695789692481670862
LIMITS
unlike sin and cos, x must be real
0 < x <= 1
eps > 0
LIBRARY
NUMBER *qasech(NUMBER *x, NUMBER *eps)
SEE ALSO
asinh, acosh, atanh, acsch, acoth, epsilon

32
help/asin Normal file
View File

@@ -0,0 +1,32 @@
NAME
asin - inverse trigonometric sine
SYNOPSIS
asin(x [,eps])
TYPES
x real, -1 <= x <= 1
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the asin of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = asin(x) is the number in [-p1/2, pi/2] for which sin(v) = x.
EXAMPLE
> print asin(.5, 1e-5), asin(.5, 1e-10), asin(.5, 1e-15), asin(.5, 1e-20)
.5236 .5235987756 .523598775598299 .52359877559829887308
LIMITS
unlike sin and cos, x must be real
abs(x) <= 1
eps > 0
LIBRARY
NUMBER *qasin(NUMBER *q, NUMBER *epsilon)
SEE ALSO
acos, atan, asec, acsc, acot, epsilon

32
help/asinh Normal file
View File

@@ -0,0 +1,32 @@
NAME
asinh - inverse hyperbolic sine
SYNOPSIS
asinh(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the asinh of x to a multiple of eps with error less in
absolute value than .75 * eps.
asinh(x) = ln(x + sqrt(1 + x^2)) is the real number v for which
sinh(v) = x.
EXAMPLE
> print asinh(2, 1e-5), asinh(2, 1e-10), asinh(2, 1e-15), asinh(2, 1e-20)
1.44363 1.4436354752 1.44363547517881 1.44363547517881034249
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qasinh(NUMBER *x, NUMBER *eps)
SEE ALSO
acosh, atanh, asech, acsch, acoth, epsilon

29
help/assign Normal file
View File

@@ -0,0 +1,29 @@
NAME
=
SYNOPSIS
a = b
TYPES
a lvalue
b expression
return lvalue
DESCRIPTION
a = b evaluates b, assigns its value to a, and returns a.
EXAMPLE
> b = 3+1
> a = b
> print a, b
4 4
LIMITS
none
LIBRARY
none
SEE ALSO
XXX - fill in

79
help/assoc Normal file
View File

@@ -0,0 +1,79 @@
NAME
assoc - create a new association array
SYNOPSIS
assoc()
TYPES
return association
DESCRIPTION
This functions returns an empty association array.
Associations are special values that act like matrices, except
that they are more general (and slower) than normal matrices.
Unlike matrices, associations can be indexed by arbitrary values.
For example, if 'val' was an association, you could do the following:
val['hello'] = 11;
val[4.5] = val['hello'];
print val[9/2];
and 11 would be printed.
Associations are created by the 'assoc' function. It takes no
arguments, and simply returns an empty association. You can then
insert elements into the association by indexing the returned value
as shown above.
Associations are multi-dimensional. You can index them using one to
four dimensions as desired, and the elements with different numbers
of dimensions will remain separated. For example, 'val[3]' and
'val[3,0]' can both be used in the same association and will be
distinct elements.
When references are made to undefined elements of an association,
a null value is simply returned. Therefore no bounds errors can
occur when indexing an association. Assignments of a null value
to an element of an association does not delete the element, but
a later reference to that element will return the null value as if
the element was undefined. Elements with null values are implicitly
created on certain other operations which require an address to be
taken, such as the += operator and using & in a function call.
The elements of an association are stored in a hash table for
quick access. The index values are hashed to select the correct
hash chain for a small sequential search for the element. The hash
table will be resized as necessary as the number of entries in
the association becomes larger.
The size function returns the number of elements in an association.
This size will include elements with null values.
Double bracket indexing can be used for associations to walk through
the elements of the association. The order that the elements are
returned in as the index increases is essentially random. Any
change made to the association can reorder the elements, this making
a sequential scan through the elements difficult.
The search and rsearch functions can search for an element in an
association which has the specified value. They return the index
of the found element, or a NULL value if the value was not found.
Associations can be copied by an assignment, and can be compared
for equality. But no other operations on associations have meaning,
and are illegal.
EXAMPLE
> print assoc()
assoc (0 elements):
LIMITS
none
LIBRARY
none
SEE ALSO
isassoc, rsearch, search, size

31
help/atan Normal file
View File

@@ -0,0 +1,31 @@
NAME
atan - inverse trigonometric tangent
SYNOPSIS
atan(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the atan of x to a multiple of eps with error less in
absolute value than .75 * eps.
v = atan(x) is the number in (-p1/2, pi/2) for which tan(v) = x.
EXAMPLE
> print atan(2, 1e-5), atan(2, 1e-10), atan(2, 1e-15), atan(2, 1e-20)
1.10715 1.1071487178 1.107148717794091 1.10714871779409050302
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qatan(NUMBER *x, NUMBER *eps)
SEE ALSO
asin, acos, asec, acsc, acot, epsilon

36
help/atan2 Normal file
View File

@@ -0,0 +1,36 @@
NAME
atan2 - angle to point
SYNOPSIS
atan2(y, x, [,acc])
TYPES
y real
x real
acc real
return real
DESCRIPTION
Return the angle which is determined by the point (x,y). This
function computes the arctangent of y/x in the range [-pi, pi].
The value acc specifies the accuracy of the result. By default, acc
is epsilon().
Note that by convention, y is the first argument.
To conform to the 4.3BSD ANSI/IEEE 754-1985 math lib, atan2(0,0) is
defined to return 0.
EXAMPLE
> print atan2(0,0), atan2(1,sqrt(3)), atan2(17,53,1e-100)
0 ~.52359877559829887307 ~.31038740713235146535
LIMITS
acc > 0
LIBRARY
NUMBER *qatan2(NUMBER *y, *x, *acc)
SEE ALSO
acos, asin, atan, cos, epsilon, sin, tan

32
help/atanh Normal file
View File

@@ -0,0 +1,32 @@
NAME
atanh - inverse hyperbolic tangent
SYNOPSIS
atanh(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Returns the atanh of x to a multiple of eps with error less in
absolute value than .75 * eps.
atanh(x) = ln((1 + x)/(1 - x))/2 is the real number v for whichi
tanh(v) = x.
EXAMPLE
> print atanh(.5,1e-5), atanh(.5,1e-10), atanh(.5,1e-15), atanh(.5,1e-20)
.54931 .5493061443 .549306144334055 .5493061443340548457
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qatanh(NUMBER *x, NUMBER *eps)
SEE ALSO
asinh, acosh, asech, acsch, acoth, epsilon

50
help/avg Normal file
View File

@@ -0,0 +1,50 @@
NAME
avg - average (arithmetic) mean of values
SYNOPSIS
avg(x_1, x_2, ...)
TYPES
x_1, ... arithmetic or list
return as determined by types of items averaged
DESCRIPTION
If there are n non-list arguments x_1, x_2, ..., x_n,
for which the required additions and division by n are defined,
avg(x_1, x_2, ..., x_n) returns the value of:
(x_1 + x_2 + ... + x_n)/n.
If the x_i are real, the result will be a real number; if the
x_i are real or complex numbers, the result will be a real or complex
number. If the x_i are summable matrices the result will be a matrix
of the same size (e.g. if the x_i are all 3 x 4 matrices with real
entries, the result will be a 3 x 4 matrix with real entries).
If an argument x_i is list-valued, e.g. list(y_1, y_2, ...), this
is treated as contributing y_1, y_2, ... to the list of items to
be averaged.
EXAMPLE
> print avg(1,2,3,4,5), avg(list(1,2,3,4,5)), avg(1,2,list(3,4,5))
3 3 3
> mat x[2,2] = {1,2,3,4}
> mat y[2,2] = {1,2,4,8}
> avg(x,y)
mat [2,2] (4 elements, 4 nonzero):
[0,0] = 1
[0,1] = 2
[1,0] = 3.5
[1,1] = 6
LIMITS
The number of arguments is not to exceed 100.
LIBRARY
none
SEE ALSO
hmean

55
help/base Normal file
View File

@@ -0,0 +1,55 @@
NAME
base - set default output base
SYNOPSIS
base([mode])
TYPES
mode real
return real
DESCRIPTION
The base function allows one to specify how numbers should be
printer. The base function provides a numeric shorthand to the
config("mode") interface. With no args, base() will return the
current mode. With 1 arg, base(val) will set the mode according to
the arg and return the previous mode.
The following convention is used to declare modes:
base config
value string
2 "binary" binary fractions
8 "octal" octal fractions
10 "real" decimal floating point
16 "hex" hexadecimal fractions
-10 "int" decimal integer
1/3 "frac" decimal fractions
1e20 "exp" decimal exponential
For convenience, any non-integer value is assumed to mean "frac",
and any integer >= 2^64 is assumed to mean "exp".
EXAMPLE
> base()
10
> base(8)
012
> print 10
012
LIMITS
none
LIBRARY
int math_setmode(int newmode)
NOTE: newmode must be one of MODE_DEFAULT, MODE_FRAC, MODE_INT,
MODE_REAL, MODE_EXP, MODE_HEX, MODE_OCTAL, MODE_BINARY
SEE ALSO
config

123
help/bround Normal file
View File

@@ -0,0 +1,123 @@
NAME
bround - round numbers to a specified number of binary digits
SYNOPSIS
bround(x [,plcs [, rnd]])
TYPES
If x is a matrix or a list, bround(x[[i]], ...) is to return
a value for each element x[[i]] of x; the value returned will be
a matrix or list with the same structure as x.
Otherwise, if x is an object of type tt, or if x is not an object or
number but y is an object of type tt, and the function tt_bround has
to be defined; the types for x, plcs, rnd, and the returned value,
if any, are as required for specified in tt_bround. For the object
case, plcs and rnd default to the null value.
For other cases:
x number (real or complex)
plcs integer, defaults to zero
rnd integer, defaults to config("round")
return number
DESCRIPTION
For real x, bround(x, plcs, rnd) returns x rounded to either
plcs significant binary digits (if rnd & 32 is nonzero) or to plcs
binary places (if rnd & 32 is zero). In the significant-figure
case the rounding is to plcs - ilog10(x) - 1 binary places.
If the number of binary places is n and eps = 10^-n, the
result is the same as for appr(x, eps, rnd). This will be
exactly x if x is a multiple of eps; otherwise rounding occurs
to one of the nearest multiples of eps on either side of x. Which
of these multiples is returned is determined by z = rnd & 31, i.e.
the five low order bits of rnd, as follows:
z = 0 or 4: round down, i.e. towards minus infinity
z = 1 or 5: round up, i.e. towards plus infinity
z = 2 or 6: round towards zero
z = 3 or 7: round away from zero
z = 8 or 12: round to the nearest even multiple of eps
z = 9 or 13: round to the nearest odd multiple of eps
z = 10 or 14: round to nearest even or odd multiple of eps
according as x > or < 0
z = 11 or 15: round to nearest odd or even multiple of eps
according as x > or < 0
z = 16 to 31: round to the nearest multiple of eps when
this is uniquely determined. Otherwise
rounding is as if z is replaced by z - 16
For complex x:
The real and imaginary parts are rounded as for real x; if the
imaginary part rounds to zero, the result is real.
For matrix or list x:
The returned values has element bround(x[[i]], plcs, rnd) in
the same position as x[[i]] in x.
For object x or plcs:
When bround(x, plcs, rnd) is called, x is passed by address so may be
changed by assignments; plcs and rnd are copied to temporary
variables, so their values are not changed by the call.
EXAMPLES
> a = 7/32, b = -7/32
> print a, b
.21875 -.21875
> print round(a,3,0), round(a,3,1), round(a,3,2), print round(a,3,3)
.218, .219, .218, .219
> print round(b,3,0), round(b,3,1), round(b,3,2), print round(b,3,3)
-.219, -.218, -.218, -.219
> print round(a,3,16), round(a,3,17), round(a,3,18), print round(a,3,19)
.2188 .2188 .2188 .2188
> print round(a,4,16), round(a,4,17), round(a,4,18), print round(a,4,19)
.2187 .2188 .2187 .2188
> print round(a,2,8), round(a,3,8), round(a,4,8), round(a,5,8)
.22 .218 .2188 .21875
> print round(a,2,24), round(a,3,24), round(a,4,24), round(a,5,24)
.22 .219 .2188 .21875
> c = 21875
> print round(c,-2,0), round(c,-2,1), round(c,-3,0), round(c,-3,16)
21800 21900 21000 22000
> print round(c,2,32), round(c,2,33), round(c,2,56), round(c,4,56)
21000 22000 22000 21880
> A = list(1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8)
> print round(A,2,24)
list(7 elements, 7 nonzero):
[[0]] = .12
[[1]] = .25
[[3]] = .38
[[4]] = .5
[[5]] = .62
[[6]] = .75
[[7]] = .88
LIMITS
For non-object case:
0 <= abs(plcs) < 2^31
0 <= abs(rnd) < 2^31
LIBRARY
void broundvalue(VALUE *x, VALUE *plcs, VALUE *rnd, VALUE *result)
MATRIX *matbround(MATRIX *m, VALUE *plcs, VALUE *rnd);
LIST *listbround(LIST *m, VALUE *plcs, VALUE *rnd);
NUMBER *qbround(NUMBER *m, long plcs, long rnd);
SEE ALSO
round, trunc, btrunc, int, appr

36
help/btrunc Normal file
View File

@@ -0,0 +1,36 @@
NAME
btrunc - truncate a value to a number of binary places
SYNOPSIS
btrunc(x [,j])
TYPES
x real
j int
return real
DESCRIPTION
Truncate x to j binary places. If j is omitted, 0 places is assumed.
Specifying zero places makes the result identical to int().
Truncation of a non-integer prodcues values nearer to zero.
EXAMPLE
> print btrunc(pi()), btrunc(pi(), 10)
3 3.140625
> print btrunc(3.3), btrunc(3.7), btrunc(3.3, 2), btrunc(3.7, 2)
3 3 3.25 3.5
> print btrunc(-3.3), btrunc(-3.7), btrunc(-3.3, 2), btrunc(-3.7, 2)
-3 -3 -3.25 -3.5
LIMITS
0 <= j < 2^31
LIBRARY
NUMBER *qbtrunc(NUMBER *x, *j)
SEE ALSO
bround, int, round, trunc

200
help/builtin.end Normal file
View File

@@ -0,0 +1,200 @@
The config function sets or reads the value of a configuration
parameter. The first argument is a string which names the parameter
to be set or read. If only one argument is given, then the current
value of the named parameter is returned. If two arguments are given,
then the named parameter is set to the value of the second argument,
and the old value of the parameter is returned. Therefore you can
change a parameter and restore its old value later. The possible
parameters are explained in the next section.
The scale function multiplies or divides a number by a power of 2.
This is used for fractional calculations, unlike the << and >>
operators, which are only defined for integers. For example,
scale(6, -3) is 3/4.
The quomod function is used to obtain both the quotient and remainder
of a division in one operation. The first two arguments a and b are
the numbers to be divided. The last two arguments c and d are two
variables which will be assigned the quotient and remainder. For
nonnegative arguments, the results are equivalent to computing a//b
and a%b. If a is negative and the remainder is nonzero, then the
quotient will be one less than a//b. This makes the following three
properties always hold: The quotient c is always an integer. The
remainder d is always 0 <= d < b. The equation a = b * c + d always
holds. This function returns 0 if there is no remainder, and 1 if
there is a remainder. For examples, quomod(10, 3, x, y) sets x to 3,
y to 1, and returns the value 1, and quomod(-4, 3.14159, x, y) sets x
to -2, y to 2.28318, and returns the value 1.
The eval function accepts a string argument and evaluates the
expression represented by the string and returns its value.
The expression can include function calls and variable references.
For example, eval("fact(3) + 7") returns 13. When combined with
the prompt function, this allows the calculator to read values from
the user. For example, x=eval(prompt("Number: ")) sets x to the
value input by the user.
The digit and isset functions return individual digits of a number,
either in base 10 or in base 2, where the lowest digit of a number
is at digit position 0. For example, digit(5678, 3) is 5, and
isset(0b1000100, 2) is 1. Negative digit positions indicate places
to the right of the decimal or binary point, so that for example,
digit(3.456, -1) is 4.
The ptest builtin is a primality testing function. The
1st argument is the suspected prime to be tested. The
absolute value of the 2nd argument is an iteration count.
If ptest is called with only 2 args, the 3rd argument is
assumed to be 0. If ptest is called with only 1 arg, the
2nd argument is assumed to be 1. Thus, the following
calls are equivalent:
ptest(a)
ptest(a,1)
ptest(a,1,0)
Normally ptest performs a some checks to determine if the
value is divisable by some trivial prime. If the 2nd
argument is < 0, then the trivial check is omitted.
For example, ptest(a,10) performs the same work as:
ptest(a,-3) (7 tests without trivial check)
ptest(a,-7,3) (3 more tests without the trivial check)
The ptest function returns 0 if the number is definitely not
prime, and 1 is the number is probably prime. The chance
of a number which is probably prime being actually composite
is less than 1/4 raised to the power of the iteration count.
For example, for a random number p, ptest(p, 10) incorrectly
returns 1 less than once in every million numbers, and you
will probably never find a number where ptest(p, 20) gives
the wrong answer.
The first 3 args of nextcand and prevcand functions are the same
arguments as ptest. But unlike ptest, nextcand and prevcand return
the next and previous values for which ptest is true.
For example, nextcand(2^1000) returns 2^1000+297 because
2^1000+297 is the smallest value x > 2^1000 for which
ptest(x,1) is true. And for example, prevcand(2^31-1,10,5)
returns 2147483629 (2^31-19) because 2^31-19 is the largest
value y < 2^31-1 for which ptest(y,10,5) is true.
The nextcand and prevcand functions also have a 5 argument form:
nextcand(num, count, skip, modval, modulus)
prevcand(num, count, skip, modval, modulus)
return the smallest (or largest) value ans > num (or < num) that
is also == modval % modulus for which ptest(ans,count,skip) is true.
The builtins nextprime(x) and prevprime(x) return the
next and previous primes with respect to x respectively.
As of this release, x must be < 2^32. With one argument, they
will return an error if x is out of range. With two arguments,
they will not generate an error but instead will return y.
The builtin function pix(x) returns the number of primes <= x.
As of this release, x must be < 2^32. With one argument, pix(x)
will return an error if x is out of range. With two arguments,
pix(x,y) will not generate an error but instead will return y.
The builtin function factor may be used to search for the
smallest factor of a given number. The call factor(x,y)
will attempt to find the smallest factor of x < min(x,y).
As of this release, y must be < 2^32. If y is omitted, y
is assumed to be 2^32-1.
If x < 0, factor(x,y) will return -1. If no factor <
min(x,y) is found, factor(x,y) will return 1. In all other
cases, factor(x,y) will return the smallest prime factor
of x. Note except for the case when abs(x) == 1, factor(x,y)
will not return x.
If factor is called with y that is too large, or if x or y
is not an integer, calc will report an error. If a 3rd argument
is given, factor will return that value instead. For example,
factor(1/2,b,c) will return c instead of issuing an error.
The builtin lfactor(x,y) searches a number of primes instead
of below a limit. As of this release, y must be <= 203280221
(y <= pix(2^32-1)). In all other cases, lfactor is operates
in the same way as factor.
If lfactor is called with y that is too large, or if x or y
is not an integer, calc will report an error. If a 3rd argument
is given, lfactor will return that value instead. For example,
lfactor(1/2,b,c) will return c instead of issuing an error.
The lfactor function is slower than factor. If possible factor
should be used instead of lfactor.
The builtin isprime(x) will attempt to determine if x is prime.
As of this release, x must be < 2^32. With one argument, isprime(x)
will return an error if x is out of range. With two arguments,
isprime(x,y) will not generate an error but instead will return y.
The functions rcin, rcmul, rcout, rcpow, and rcsq are used to
perform modular arithmetic calculations for large odd numbers
faster than the usual methods. To do this, you first use the
rcin function to convert all input values into numbers which are
in a format called REDC format. Then you use rcmul, rcsq, and
rcpow to multiply such numbers together to produce results also
in REDC format. Finally, you use rcout to convert a number in
REDC format back to a normal number. The addition, subtraction,
negation, and equality comparison between REDC numbers are done
using the normal modular methods. For example, to calculate the
value 13 * 17 + 1 (mod 11), you could use:
p = 11;
t1 = rcin(13, p);
t2 = rcin(17, p);
t3 = rcin(1, p);
t4 = rcmul(t1, t2, p);
t5 = (t4 + t3) % p;
answer = rcout(t5, p);
The swap function exchanges the values of two variables without
performing copies. For example, after:
x = 17;
y = 19;
swap(x, y);
then x is 19 and y is 17. This function should not be used to
swap a value which is contained within another one. If this is
done, then some memory will be lost. For example, the following
should not be done:
mat x[5];
swap(x, x[0]);
The hash function returns a relatively small non-negative integer
for one or more input values. The hash values should not be used
across runs of the calculator, since the algorithms used to generate
the hash value may change with different versions of the calculator.
The base function allows one to specify how numbers should be
printer. The base function provides a numeric shorthand to the
config("mode") interface. With no args, base() will return the
current mode. With 1 arg, base(val) will set the mode according to
the arg and return the previous mode.
The following convention is used to declare modes:
base config
value string
2 "binary" binary fractions
8 "octal" octal fractions
10 "real" decimal floating point
16 "hex" hexadecimal fractions
-10 "int" decimal integer
1/3 "frac" decimal fractions
1e20 "exp" decimal exponential
For convenience, any non-integer value is assumed to mean "frac",
and any integer >= 2^64 is assumed to mean "exp".

9
help/builtin.top Normal file
View File

@@ -0,0 +1,9 @@
Builtin functions
There is a large number of built-in functions. Many of the
functions work on several types of arguments, whereas some only
work for the correct types (e.g., numbers or strings). In the
following description, this is indicated by whether or not the
description refers to values or numbers. This display is generated
by the 'show builtin' command.

33
help/ceil Normal file
View File

@@ -0,0 +1,33 @@
NAME
ceil - ceiling
SYNOPSIS
ceil(x)
TYPES
x real, complex, list, matrix
return real or complex, list, matrix
DESCRIPTION
For real x, ceil(x) is the least integer not less than x.
For complex, ceil(x) returns the real or complex number v for
which re(v) = ceil(re(x)), im(v) = ceil(im(x)).
For list or matrix x, ceil(x) returns the list or matrix of the
same structure as x for which each element t of x has been replaced
by ceil(t).
EXAMPLE
> print ceil(27), ceil(1.23), ceil(-4.56), ceil(7.8 - 9.1i)
27 2 -4 8-9i
LIMITS
none
LIBRARY
none
SEE ALSO
floor, int

89
help/cfappr Normal file
View File

@@ -0,0 +1,89 @@
NAME
cfappr - approximate a real number using continued fractions
SYNOPSIS
cfappr(x [,eps [,rnd]]) or cfappr(x, n [,rnd])
TYPES
x real
eps real with abs(eps) < 1, defaults to epsilon()
n real with n >= 1
rnd integer, defaults to config("cfappr")
return real
DESCRIPTION
If x is an integer or eps is zero, either form returns x.
If abs(eps) < 1, cfappr(x, eps) returns the smallest-denominator
number in one of the three intervals, [x, x + abs(eps)],
[x - abs(eps], x], [x - abs(eps)/2, x + abs(eps)/2].
If n >= 1 and den(x) > n, cfappr(x, n) returns the nearest above,
nearest below, or nearest, approximation to x with denominator less
than or equal to n. If den(x) <= n, cfappr(x,n) returns x.
In either case when the result v is not x, how v relates to x is
determined by bits 0, 1, 2 and 4 of the argument rnd in the same way as
these bits are used in the functions round() and appr(). In the
following y is either eps or n.
rnd sign of remainder x - v
0 sgn(y)
1 -sgn(y
2 sgn(x), "rounding to zero"
3 -sgn(x), "rounding from zero"
4 +, "rounding down"
5 -, "rounding up"
6 sgn(x/y)
7 -sgn(x/y)
If bit 4 of rnd is set, the other bits are irrelevant for the eps case;
thus for 16 <= rnd < 24, cfappr(x, eps, rnd) is the smallest-denominator
number differing from x by at most abs(eps)/2.
If bit 4 of rnd is set and den(x) > 2, the other bits are irrelevant for
the bounded denominator case; in the case of two equally near nearest
approximations with denominator less than n, cfappr(x, n, rnd)
returns the number with smaller denominator. If den(x) = 2, bits
0, 1 and 2 of rnd are used as described above.
If -1 < eps < 1, cfappr(x, eps, 0) may be described as the smallest
denominator number in the closed interval with end-points x and x - eps.
It follows that if abs(a - b) < 1, cfappr(a, a - b, 0) gives the smallest
denominator number in the interval with end-points a and b; the same
result is returned by cfappr(b, b - a, 0) or cfappr(a, b - a, 1).
If abs(eps) < 1 and v = cfappr(x, eps, rnd), then
cfappr(x, sgn(eps) * den(v), rnd) = v.
If 1 <= n < den(x), u = cfappr(x, n, 0) and v = cfappr(x, n, 1), then
u < x < v, den(u) <= n, den(v) <= n, den(u) + den(v) > n, and
v - u = 1/(den(u) * den(v)).
If x is not zero, the nearest approximation with numerator not
exceeding n is 1/cfappr(1/x, n, 16).
EXAMPLE
> c = config("mode", "frac")
> x = 43/30; u = cfappr(x, 10, 0); v = cfappr(x, 10, 1);
> print u, v, x - u, v - x, v - u, cfappr(x, 10, 16)
10/7 13/9 1/210 1/90 1/63 10/7
> pi = pi(1e-10)
> print cfappr(pi, 100, 16), cfappr(pi, .01, 16), cfappr(pi, 1e-6, 16)
311/99 22/7 355/113
> x = 17/12; u = cfappr(x,4,0); v = cfappr(x,4,1);
> print u, v, x - u, v - x, cfappr(x,4,16)
4/3 3/2 1/12 1/12 3/2
LIMITS
none
LIBRARY
NUMBER *qcfappr(NUMBER *q, NUMBER *epsilon, long R)
SEE ALSO
appr, cfsim

114
help/cfsim Normal file
View File

@@ -0,0 +1,114 @@
NAME
cfsim - simplify a value using continued fractions
SYNOPSIS
cfsim(x [,rnd])
TYPES
x real
rnd integer, defaults to config("cfsim")
return real
DESCRIPTION
If x is not an integer, cfsim(x, rnd) returns either the nearest
above x, or the nearest below x, number with denominator less than
den(x). If x is an integer, cfsim(x, rnd) returns x + 1, x - 1, or 0.
Which of the possible results is returned is controlled
by bits 0, 1, 3 and 4 of the parameter rnd.
For 0 <= rnd < 4, the sign of the remainder x - cfsim(x, rnd) is
as follows:
rnd sign of x - cfsim(x, rnd)
0 +, as if rounding down
1 -. as if rounding up
2 sgn(x), as if rounding to zero
3 -sgn(x), as if rounding from zero
This corresponds to the use of rnd for functions like round(x, n, rnd).
If bit 3 or 4 of rnd is set, the lower order bits are ignored; bit 3
is ignored if bit 4 is set. Thusi, for rnd > 3, it sufficient to
consider the two cases rnd = 8 and rnd = 16.
If den(x) > 2, cfsim(x, 8) returns the value of the penultimate simple
continued-fraction approximant to x, i.e. if:
x = a_0 + 1/(a_1 + 1/(a_2 + ... + 1/a_n) ...)),
where a_0 is an integer, a_1, ..., a_n are positive integers,
and a_n >= 2, the value returned is that of the continued fraction
obtained by dropping the last quotient 1/a_n.
If den(x) > 2, cfsim(x, 16) returns the nearest number to x with
denominator less than den(x). In the continued-fraction representation
of x described above, this is given by replacing a_n by a_n - 1.
If den(x) = 2, the definition adopted is to round towards zero for the
approximant case (rnd = 8) and from zero for the "nearest" case (rnd = 16).
For integral x, cfsim(x, 8) returns zero, cfsim(x,16) returns x - sgn(x).
In summary, for cfsim(x, rnd) when rnd = 8 or 16, the results are:
rnd integer x half-integer x den(x) > 2
8 0 x - sgn(x)/2 approximant
16 x - sgn(x) x + sgn(x)/2 nearest
From either cfsim(x, 0) and cfsim(x, 1), the other is easily
determined: if one of them has value w, the other has value
(num(x) - num(w))/(den(x) - den(w)). From x and w one may find
other optimal rational numbers near x; for example, the smallest-
denominator number between x and w is (num(x) + num(w))/(den(x) + den(w)).
If x = n/d and cfsim(x, 8) = u/v, then for k * v < d, the k-th member of
the sequence of nearest approximations to x with decreasing denominators
on the other side of x is (n - k * u)/(d - k * v). This is nearer
to or further from x than u/v according as 2 * k * v < or > d.
Iteration of cfsim(x,8) until an integer is obtained gives a sequence of
"good" approximations to x with decreasing denominators and
correspondingly decreasing accuracy; each denominator is less than half
the preceding denominator. (Unlike the "forward" sequence of
continued-fraction approximants these are not necessarily alternately
greater than and less than x.)
Some other properties:
For rnd = 0 or 1 and any x, or rnd = 8 or 16 and x with den(x) > 2:
cfsim(n + x, rnd) = n + cfsim(x, rnd).
This equation also holds for the other values of rnd if n + x and x
have the same sign.
For rnd = 2, 3, 8 or 16, and any x:
cfsim(-x, rnd) = -cfsim(x, rnd).
If rnd = 8 or 16, except for integer x or 1/x for rnd = 8, and
zero x for rnd = 16:
cfsim(1/x, rnd) = 1/cfsim(x, rnd).
EXAMPLE
> c = config("mode", "frac");
> print cfsim(43/30, 0), cfsim(43/30, 1), cfsim(43/30, 8), cfsim(43/30,16)
10/7 33/23 10/7 33/23
> x = pi(1e-20); c = config("mode", "frac");
> while (!isint(x)) {x = cfsim(x,8); if (den(x) < 1e6) print x,:;}
1146408/364913 312689/99532 104348/33215 355/113 22/7 3
LIMITS
none
LIBRARY
NUMBER *qcfsim(NUMBER *x, long rnd)
SEE ALSO
cfappr

27
help/char Normal file
View File

@@ -0,0 +1,27 @@
NAME
char - character corresponding to a value
SYNOPSIS
char(j)
TYPES
j integer, 0 <= j < 256
return string
DESCRIPTION
For j > 0, returns a string of length 1 with a character that has
the same value as j. For j = 0, returns the null string "".
EXAMPLE
> print char(0102), char(0x6f), char(119), char(0145), char(0x6e)
B o w e n
LIMITS
none
LIBRARY
none
SEE ALSO
ord

26
help/cmdbuf Normal file
View File

@@ -0,0 +1,26 @@
NAME
cmdbuf - print the command buffer
SYNOPSIS
cmdbuf()
TYPES
return str
DESCRIPTION
This function returns the command string that was formed by calc based
on its command line arguments. If calc was invoked without arguments,
this function will return an empty string.
EXAMPLE
> cmdbuf("")
""
LIMITS
none
LIBRARY
none
SEE ALSO
XXX - fill in

90
help/cmp Normal file
View File

@@ -0,0 +1,90 @@
NAME
cmp - compare two values
SYNOPSIS
cmp(x, y)
TYPES
If x is an object of type xx or x is not an object and y is an object
of type xx, the funcion xx_cmp has to have been defined; any
further conditions on x and y, and the type of the returned
value depends on the definition of xx_cmp.
For non-object x and y:
x number or string
y same as x
return -1, 0, 1 (real & string)
-1, 0, 1, -1+1i, 1i, 1+1i, -1-1i, -1i or 1-1i (complex)
DESCRIPTION
Compare two values and return a value based on their relationship.
Comparison by type is indicated below. Where more than one test is
indicated, tests are performed in the order listed. If the test is
inconclusive, the next test is performed. If all tests are
inconclusive, the values are considered equivalent.
real (returns -1, 0, or 1)
the greater number is greater
complex (returns -1, 0, 1, -1+1i, 1i, 1+1i, -1-1i, -1i or 1-1i)
sgn(re(x) - re(y)) + sgn(im(x) - im(y)) * 1i
string (returns -1, 0, or 1)
the string with the greater first different character is greater
the longer string is greater
object (depends on xx_cmp)
the greater object as defined by xx_cmp is greater
String comparison is performed via the strcmp() libc function.
Note that this function is not a substitution for equality. The ==
operator always takes epsilon() into account when comparing numeric
values. For example:
> cmp(1, 1+epsilon()/2)
-1
> 1 == 1+epsilon()/2
0
It should be noted epsilon() is used when comparing complex values.
Properties of cmp(a,b) for real or complex a and b are:
cmp(a + c, b + c) = cmp(a,b)
cmp(a, b) == 0 if and only if a == b
cmp(b, a) = -cmp(a,b)
if c is real or pure imaginary, cmp(c * a, c * b) = c * cmp(a,b)
cmp(a,b) == cmp(b,c) if and only if b is "between" a and c
The numbers between 2 + 3i and 4 + 5i are those with real part between
2 and 4, imaginary part between 3 and 5; the numbers between 2 + 3i
and 4 + 3i are those with real part between 2 and 4, imaginary part = 3.
EXAMPLE
> print cmp(3,4), cmp(4,3), cmp(4,4), cmp("a","b"), cmp("abcd","abc")
-1 1 0 -1 1
> print cmp(3,4i), cmp(4,4i), cmp(5,4i), cmp(-5,4i), cmp(-4i,5), cmp(-4i,-5)
1-1i 1-1i 1-1i -1-1i -1-1i 1-1i
> print cmp(3i,4i), cmp(4i,4i), cmp(5i,4i), cmp(3+4i,5), cmp(3+4i,-5)
-1i 0 1i -1+1i 1+1i
> print cmp(3+4i,3+4i), cmp(3+4i,3-4i), cmp(3+4i,2+3i), cmp(3+4i,-4-5i)
0 1i 1+1i 1+1i
LIMITS
none
LIBRARY
none
SEE ALSO
abs, epsilon, sgn

39
help/comb Normal file
View File

@@ -0,0 +1,39 @@
NAME
comb - combinatorial number
SYNOPSIS
comb(x, y)
TYPES
x int
y int
return int
DESCRIPTION
Return the combinatorial number C(x,y) which is defined as:
x!
---------
y!*(x-y)!
This function computes the number of combinations in which y things
may be chosen from x items ignoring the order in which they are chosen.
EXAMPLE
> print comb(7,3), comb(7,4), comb(7,5), comb(3,0), comb(0,0)
35 35 21 1 1
> print comb(2^31+1,2^31-1)
2305843010287435776
LIMITS
x >= y >= 0
y < 2^24
x-y < 2^24
LIBRARY
void zcomb(NUMBER x, y, *ret)
SEE ALSO
fact, perm

99
help/command Normal file
View File

@@ -0,0 +1,99 @@
Command sequence
This is a sequence of any the following command formats, where
each command is terminated by a semicolon or newline. Long command
lines can be extended by using a back-slash followed by a newline
character. When this is done, the prompt shows a double angle
bracket to indicate that the line is still in progress. Certain
cases will automatically prompt for more input in a similar manner,
even without the back-slash. The most common case for this is when
a function is being defined, but is not yet completed.
Each command sequence terminates only on an end of file. In
addition, commands can consist of expression sequences, which are
described in the next section.
NOTE: Calc commands are in lower case. UPPER case is used below
for emphasis only, and should be considered in lower case.
DEFINE function(params) { body }
DEFINE function(params) = expression
This first form defines a full function which can consist
of declarations followed by many statements which implement
the function.
The second form defines a simple function which calculates
the specified expression value from the specified parameters.
The expression cannot be a statement. However, the comma
and question mark operators can be useful. Examples of
simple functions are:
define sumcubes(a, b) = a^3 + b^3;
define pimod(a) = a % pi();
HELP
This displays a general help message.
READ filename
This reads definitions from the specified filename.
The name can be quoted if desired. The calculator
uses the CALCPATH environment variable to search
through the specified directories for the filename,
similarly to the use of the PATH environment variable.
If CALCPATH is not defined, then a default path which is
usually ":/usr/local/lib/calc" is used (that is, the current
directory followed by a general calc library directory).
The ".cal" extension is defaulted for input files, so
that if "filename" is not found, then "filename.cal" is
then searched for. The contents of the filename are
command sequences which can consist of expressions to
evaluate or functions to define, just like at the top
level command level.
If the -m mode disallows opening of files for reading,
this command will be disabled.
READ -once filename
This command acts like the regular READ expect that it
will ignore filename if is has been previously read.
This command is particularly useful in a library that
needs to read a 2nd library. By using the READ -once
command, one will not reread that 2nd library, nor will
once risk entering into a infinite READ loop (where
that 2nd library directly or indirectly does a READ of
the first library).
If the -m mode disallows opening of files for reading,
this command will be disabled.
WRITE filename
This writes the values of all global variables to the
specified filename, in such a way that the file can be
later read in order to recreate the variable values.
For speed reasons, values are written as hex fractions.
This command currently only saves simple types, so that
matrices, lists, and objects are not saved. Function
definitions are also not saved.
If the -m mode disallows opening of files for writing,
this command will be disabled.
QUIT
This leaves the calculator, when given as a top-level
command.
CD
Change the current directory to the home directory, if $HOME
is set in the environment.
CD dir
Change the current directory to dir.
Also see the help topic:
statement flow control and declaration statements
usage for -m modes

267
help/config Normal file
View File

@@ -0,0 +1,267 @@
Configuration parameters
Configuration parameters affect how the calculator performs certain
operations. Among features that are controlled by these parameters
are the accuracy of some calculations, the displayed format of results,
the choice from possible alternative algorithms, and whether or not
debugging information is displayed. The parameters are
read or set using the "config" built-in function; they remain in effect
until their values are changed by a config or equivalent instruction.
The following parameters can be specified:
"all" all configuration values listed below
"trace" turns tracing features on or off
"display" sets number of digits in prints.
"epsilon" sets error value for transcendentals.
"maxprint" sets maximum number of elements printed.
"mode" sets printout mode.
"mul2" sets size for alternative multiply.
"sq2" sets size for alternative squaring.
"pow2" sets size for alternate powering.
"redc2" sets size for alternate REDC.
"tilde" enable/disable printing of the roundoff '~'
"tab" enable/disable printing of leading tabs
"quomod" sets rounding mode for quomod
"quo" sets rounding mode for //, default for quo
"mod" sets "rounding" mode for %, default for mod
"sqrt" sets rounding mode for sqrt
"appr" sets rounding mode for appr
"cfappr" sets rounding mode for cfappr
"cfsim" sets rounding mode for cfsim
"round" sets rounding mode for round and bround
"outround" sets rounding mode for printing of numbers
"leadzero" enables/disables printing of 0 as in 0.5
"fullzero" enables/disables padding zeros as in .5000
"maxerr" maximum number of scan errors before abort
"prompt" default interactive prompt
"more" default interactive multi-line input prompt
The "all" config value allows one to save/restore the configuration
set of values. The return of:
config("all")
is a CONFIG type which may be used as the 2rd arg in a later call.
One may save, modify and restore the configuration state as follows:
oldstate = config("all")
...
config("tab", 0)
config("mod", 10)
...
config("all", oldstate)
This save/restore method is useful within functions.
It allows functions to control their configuration without impacting
the calling function.
There are two configuration state aliases that may be set. To
set the backward compatible standard configuration:
config("all", "oldstd")
The "oldstd" will restore the configuration to the default at startup.
A new configuration that some people prefer may be set by:
config("all", "newstd")
The "newstd" is not backward compatible with the historic
configuration. Even so, some people prefer this configuration
and place the config("all", "newstd") command in their CALCRC
startup files.
When nonzero, the "trace" parameter activates one or more features
that may be useful for debugging. These features correspond to
powers of 2 which contribute additively to config("trace"):
1: opcodes are displayed as functions are evaluated
2: disables the inclusion of debug lines in opcodes for functions
whose definitions are introduced with a left-brace.
4: the number of links for real and complex numbers are displayed
when the numbers are printed; for real numbers "#" or for
complex numbers "##", followed by the number of links, are
printed immediately after the number.
8: the opcodes for a new functions are displayed when the function
is successfully defined.
The "display" parameter specifies the maximum number of digits after
the decimal point to be printed in real or exponential mode in
normal unformatted printing (print, strprint, fprint) or in
formatted printing (printf, strprintf, fprintf) when precision is not
specified. The initial value is 20. This parameter does not change
the stored value of a number. Where rounding is necessary, the type
of rounding to be used is controlled by "outround".
The "epsilon" parameter specifies the default accuracy for the
calculation of functions for which exact values are not possible or
not desired. For most functions, the
remainder = exact value - calculated value
has absolute value less than epsilon, but, except when the sign of
the remainder is controlled by an appropriate parameter, the
absolute value of the remainder usually does not exceed epsilon/2.
Functions which require an epsilon value accept an
optional argument which overrides this default epsilon value for
that single call. (The value v can be assigned to the "epsilon"
parameter by epsilon(v) as well as by config("epsilon", v), and the
current value obtained by epsilon() as well as by config("epsilon").)
For the transcendental functions and the functions sqrt() and
appr(), the calculated value is always a multiple of epsilon.
The "mode" parameter is a string specifying the mode for printing of
numbers by the unformatted print functions, and the default
("%d" specifier) for formatted print functions. The initial mode
is "real". The available modes are:
"frac" decimal fractions
"int" decimal integer
"real" decimal floating point
"exp" decimal exponential
"hex" hex fractions
"oct" octal fractions
"bin" binary fractions
The "maxprint" parameter specifies the maximum number of elements to
be displayed when a matrix or list is printed. The initial value is 16.
Mul2 and sq2 specify the sizes of numbers at which calc switches
from its first to its second algorithm for multiplying and squaring.
The first algorithm is the usual method of cross multiplying, which
runs in a time of O(N^2). The second method is a recursive and
complicated method which runs in a time of O(N^1.585). The argument
for these parameters is the number of binary words at which the
second algorithm begins to be used. The minimum value is 2, and
the maximum value is very large. If 2 is used, then the recursive
algorithm is used all the way down to single digits, which becomes
slow since the recursion overhead is high. If a number such as
1000000 is used, then the recursive algorithm is never used, causing
calculations for large numbers to slow down. For a typical example
on a 386, the two algorithms are about equal in speed for a value
of 20, which is about 100 decimal digits. A value of zero resets
the parameter back to its default value. Usually there is no need
to change these parameters.
Pow2 specifies the sizes of numbers at which calc switches from
its first to its second algorithm for calculating powers modulo
another number. The first algorithm for calculating modular powers
is by repeated squaring and multiplying and dividing by the modulus.
The second method uses the REDC algorithm given by Peter Montgomery
which avoids divisions. The argument for pow2 is the size of the
modulus at which the second algorithm begins to be used.
Redc2 specifies the sizes of numbers at which calc switches from
its first to its second algorithm when using the REDC algorithm.
The first algorithm performs a multiply and a modular reduction
together in one loop which runs in O(N^2). The second algorithm
does the REDC calculation using three multiplies, and runs in
O(N^1.585). The argument for redc2 is the size of the modulus at
which the second algorithm begins to be used.
Config("tilde") controls whether or not a leading tilde ('~') is
printed to indicate that a number has not been printed exactly
because the number of decimal digits required would exceed the
specified maximum number. The initial "tilde" value is 1.
Config ("tab") controls the printing of a tab before results
automatically displayed when working interactively. It does not
affect the printing by the functions print, printf, etc. The inital
"tab" value is 1.
The "quomod", "quo", "mod", "sqrt", "appr", "cfappr", "cfsim", and
"round" control the way in which any necessary rounding occurs.
Rounding occurs when for some reason, a calculated or displayed
value (the "approximation") has to differ from the "true value",
e.g. for quomod and quo, the quotient is to be an integer, for sqrt
and appr, the approximation is to be a multiple of an explicit or
implicit "epsilon", for round and bround (both controlled by
config("round")) the number of decimal places or fractional bits
in the approximation is limited. Zero value for any of these
parameters indicates that the true value is greater than the approximation,
i.e. the rounding is "down", or in the case of mod, that the
residue has the same sign as the divisor. If bit 4 of the
parameter is set, the rounding of to the nearest acceptable candidate
when this is uniquely determined; in the remaining ambiguous cases,
the type of rounding is determined by the lower bits of the parameter
value. If bit 3 is set, the rounding for quo, appr and sqrt,
is to the nearest even integer or the nearest even multiple of epsilon,
and for round to the nearest even "last decimal place". The effects
of the 3 lowest bits of the parameter value are as follows:
Bit 0: Unconditional reversal (down to up, even to odd, etc.)
Bit 1: Reversal if the exact value is negative
Bit 2: Reversal if the divisor or epsilon is negative
(Bit 2 is irrelevant for the functions round and bround since the
equivalent epsilon (a power of 1/10 or 1/2) is always positive.)
For quomod, the quotient is rounded to an integer value as if
evaluating quo with config("quo") == config("quomod"). Similarly,
quomod and mod give the same residues if config("mod") == config("quomod").
For the sqrt function, if bit 5 of config("sqrt") is set, the exact
square-root is returned when this is possible; otherwise the
result is rounded to a multiple of epsilon as determined by the
five lower order bits. Bit 6 of config("sqrt") controls whether the
principal or non-principal square-root is returned.
For the functions cfappr and cfsim, whether the "rounding" is down
or up, etc. is controlled by the appropriate bits of config("cfappr")
and config("cfsim") as for quomod, quo, etc.
The "outround" parameter determines the type of rounding to be used
by the various kinds of printing to the output: bits 0, 1, 3 and 4
are used in the same way as for the functions round and bround.
The "leadzero" parameter controls whether or not a 0 is printed
before the decimal point in non-zero fractions with absolute value
less than 1, e.g. whether 1/2 is printed as 0.5 or .5. The
initial value is 0, corresponding to the printing .5.
The "fullzero" parameter controls whether or not in decimal floating-
point printing, the digits are padded with zeros to reach the
number of digits specified by config("display") or by a precision
specification in formatted printing. The initial value for this
parameter is 0, so that, for example, if config("display") >= 2,
5/4 will print in "real" mode as 1.25.
The maxerr value controls how many scan errors are allowed
before the compiling phase of a computation is aborted. The initial
value of "maxerr" is 20. Setting maxerr to 0 disables this feature.
The default prompt when in teractive mode is "> ". One may change
this prompt to a more cut-and-paste friendly prompt by:
config("prompt", "; ")
On windowing systems that support cut/paste of a line, one may
cut/copy an input line and paste it directly into input. The
leading ';' will be ignored.
When inside multi-line input, the more prompt is used. One may
change it by:
config("more", ";; ")
The following are synonyms for true:
"on" "yes" "y" "true" "t" "1" any non-zero number
The following are synonyms for false:
"off" "no" "n" "false" "f" "0" the number zero (0)
Examples of setting some parameters are:
config("mode", "exp"); exponential output
config("display", 50); 50 digits of output
epsilon(epsilon() / 8); 3 bits more accuracy
config("tilde", 0) disable roundoff tilde printing
config("tab", "off") disable leading tab printing

35
help/conj Normal file
View File

@@ -0,0 +1,35 @@
NAME
conj - complex conjugate
SYNOPSIS
conj(x)
TYPES
If x is an object of type xx, conj(x) calls xx_conj(x).
For non-object x:
x real, complex, or matrix
return real, complex, or matrix
DESCRIPTION
For real x, conj(x) returns x.
For complex x, conj(x) returns re(x) - im(x) * 1i.
For matrix x, conj(x) returns a matrix of the same structure as x
in which each element t of x has been replaced by conj(t).
EXAMPLE
> print conj(3), conj(3 + 4i)
3 3-4i
LIMITS
none
LIBRARY
void conjvalue(VALUE *x, *res)
SEE ALSO
norm, abs, arg

36
help/cos Normal file
View File

@@ -0,0 +1,36 @@
NAME
cos - cosine
SYNOPSIS
cos(x [,eps])
TYPES
x number (real or complex)
eps nonzero real, defaults to epsilon()
return number
DESCRIPTION
Calculate the cosine of x to a multiple of eps with error less in
absolute value than .75 * eps.
EXAMPLE
> print cos(1, 1e-5), cos(1, 1e-10), cos(1, 1e-15), cos(1, 1e-20)
.5403 .5403023059 .54030230586814 .5403023058681397174
> print cos(2 +3i, 1e-5), cos(2 + 3i, 1e-10)
-4.18963-9.10923i -4.189625691-9.1092278938i
> pi = pi(1e-20)
> print cos(pi/3, 1e-10), cos(pi/2, 1e-10), cos(pi, 1e-10)
.5 0 -1
LIMITS
eps > 0
LIBRARY
NUMBER *qcos(NUMBER *x, NUMBER *eps)
COMPLEX *ccos(COMPLEX *x, NUMBER *eps)
SEE ALSO
sin, tan, sec, csc, cot, epsilon

31
help/cosh Normal file
View File

@@ -0,0 +1,31 @@
NAME
cosh - hyperbolic cosine
SYNOPSIS
cosh(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Calculate the cosh of x to the nearest or next to nearest multiple of
epsilon, with absolute error less than .75 * abs(eps).
cosh(x) = (exp(x) + exp(-x))/2
EXAMPLE
> print cosh(1, 1e-5), cosh(1, 1e-10), cosh(1, 1e-15), cosh(1, 1e-20)
1.54308 1.5430806348 1.543080634815244 1.54308063481524377848
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qcosh(NUMBER *x, NUMBER *eps)
SEE ALSO
sinh, tanh, sech, csch, coth, epsilon

30
help/cot Normal file
View File

@@ -0,0 +1,30 @@
NAME
cot - trigonometric cotangent
SYNOPSIS
cot(x [,eps])
TYPES
x nonzero real
acc nonzero real, defaults to epsilon()
return real
DESCRIPTION
Calculate the cotangent of x to a multiple of eps, with error less
in absolute value than .75 * eps.
EXAMPLE
> print cot(1, 1e-5), cot(1, 1e-10), cot(1, 1e-15), cot(1, 1e-20)
.64209 .6420926159 .642092615934331 .64209261593433070301
LIMITS
unlike sin and cos, x must be real
x != 0
eps > 0
LIBRARY
NUMBER *qcot(NUMBER *x, *eps)
SEE ALSO
sin, cos, tan, sec, csc, epsilon

32
help/coth Normal file
View File

@@ -0,0 +1,32 @@
NAME
coth - hyperbolic cotangent
SYNOPSIS
coth(x [,eps])
TYPES
x nonzero real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Calculate the coth of x to a multiple of eps with error less in
absolute value than .75 * eps.
coth(x) = (exp(2*x) + 1)/(exp(2*x) - 1)
EXAMPLE
> print coth(1, 1e-5), coth(1, 1e-10), coth(1, 1e-15), coth(1, 1e-20)
1.31304 1.3130352855 1.313035285499331 1.31303528549933130364
LIMITS
unlike sin and cos, x must be real
x != 0
eps > 0
LIBRARY
NUMBER *qcoth(NUMBER *x, NUMBER *eps)
SEE ALSO
sinh, cosh, tanh, sech, csch, epsilon

31
help/count Normal file
View File

@@ -0,0 +1,31 @@
NAME
count - count elements of list or matrix satisfying a stated condition
SYNOPSIS
count(x, y)
TYPES
x list or matrix
y string
return int
DESCRIPTION
For count(x, y), y is to be the name of a user-defined function;
count(x,y) then returns the number of elements of x for which y
tests as "true".
EXAMPLE
> define f(a) = (a < 5)
> A = list(1,2,7,6,4,8)
> count(A, "f")
3
LIMITS
none
LIBRARY
none
SEE ALSO
XXX - fill in

37
help/cp Normal file
View File

@@ -0,0 +1,37 @@
NAME
cp - cross product of two 3 element vectors
SYNOPSIS
cp(x, y)
TYPES
x, y 1-dimensional matrices with 3 elements
return 1-dimensional matrix with 3 elements
DESCRIPTION
Calculate the product of two 3 1-dimensional matrices.
If x has elements (x0, x1, x2), and y has elements (y0, y1, y2),
cp(x,y) returns the matrix of type [0:2] with elements:
{x1 * y2 - x2 * y1, x3 * y1 - x1 * y3, x1 * y2 - x2 * y1}
EXAMPLE
> mat x[3] = {2,3,4}
> mat y[3] = {3,4,5}
> print cp(x,y)
mat [3] (3 elements, 3 nonzero):
[0] = -1
[1] = 2
[2] = -1
LIMITS
x 1-dimensional matrix with 3 elements
y 1-dimensional matrix with 3 elements
LIBRARY
MATRIX *matcross(MATRIX *x, MATRIX *y)
SEE ALSO
dp

62
help/credit Normal file
View File

@@ -0,0 +1,62 @@
Credits
The majority of calc was written by David I. Bell.
Calc archives and calc-tester mailing list maintained by Landon Curt Noll.
Thanks for suggestions and encouragement from Peter Miller,
Neil Justusson, and Landon Noll.
Thanks to Stephen Rothwell for writing the original version of
hist.c which is used to do the command line editing.
Thanks to Ernest W. Bowen for supplying many improvements in
accuracy and generality for some numeric functions. Much of
this was in terms of actual code which I gratefully accepted.
Ernest also supplied the original text for many of the help files.
Portions of this program are derived from an earlier set of
public domain arbitrarily precision routines which was posted
to the net around 1984. By now, there is almost no recognizable
code left from that original source.
Most of this source and binary has one of the following copyrights:
Copyright (c) 19xx David I. Bell
Copyright (c) 19xx David I. Bell and Landon Curt Noll
Copyright (c) 19xx Landon Curt Noll
Copyright (c) 19xx Ernest Bowen and Landon Curt Noll
Permission is granted to use, distribute, or modify this source,
provided that this copyright notice remains intact.
Send calc comments, suggestions, bug fixes, enhancements and
interesting calc scripts that you would like you see included in
future distributions to:
dbell@auug.org.au
chongo@toad.com
Landon Noll maintains the official calc ftp archive at:
ftp://ftp.uu.net/pub/calc
Alpha test versions, complete with bugs, untested code and
experimental features may be fetched (if you are brave) under:
http://reality.sgi.com/chongo/calc/
One may join the calc testing group by sending a request to:
calc-tester-request@postofc.corp.sgi.com
Your message body (not the subject) should consist of:
subscribe calc-tester address
end
name your_full_name
where "address" is your EMail address and "your_full_name"
is your full name.
Enjoy!

29
help/csc Normal file
View File

@@ -0,0 +1,29 @@
NAME
csc - trigonometric cosecant function
SYNOPSIS
csc(x [,eps])
TYPES
x real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Calculate the cosecant of x to a multiple of eps, with error less
in absolute value than .75 * eps.
EXAMPLE
> print csc(1, 1e-5), csc(1, 1e-10), csc(1, 1e-15), csc(1, 1e-20)
1.1884 1.1883951058 1.188395105778121 1.18839510577812121626
LIMITS
unlike sin and cos, x must be real
eps > 0
LIBRARY
NUMBER *qcsc(NUMBER *x, NUMBER *eps)
SEE ALSO
sin, cos, tan, sec, cot, epsilon

32
help/csch Normal file
View File

@@ -0,0 +1,32 @@
NAME
csch - hyperbolic cosecant
SYNOPSIS
csch(x [,eps])
TYPES
x nonzero real
eps nonzero real, defaults to epsilon()
return real
DESCRIPTION
Calculate the csch of x to a multiple of epsilon, with error less in
absolute value than .75 * eps.
csch(x) = 2/(exp(x) - exp(-x))
EXAMPLE
> print csch(1, 1e-5), csch(1, 1e-10), csch(1, 1e-15), csch(1, 1e-20)
.85092 .8509181282 .850918128239322 .85091812823932154513
LIMITS
unlike sin and cos, x must be real
x != 0
eps > 0
LIBRARY
NUMBER *qcsch(NUMBER *x, NUMBER *eps)
SEE ALSO
sinh, cosh, tanh, sech, coth, epsilon

29
help/ctime Normal file
View File

@@ -0,0 +1,29 @@
NAME
ctime - current local time
SYNOPSIS
ctime()
TYPES
return string
DESCRIPTION
The ctime() builtin returns the string formed by the first 24
characters returned by the C library function, ctime():
"Mon Oct 28 00:47:00 1996"
The 25th ctime() character, '\n' is removed.
EXAMPLE
> printf("The time is now %s.\n", time())
The time is now Mon Apr 15 12:41:44 1996.
LIMITS
none
LIBRARY
none
SEE ALSO
runtime, time

68
help/define Normal file
View File

@@ -0,0 +1,68 @@
Function definitions
Function definitions are introduced by the 'define' keyword.
Other than this, the basic structure of a function is like in C.
That is, parameters are specified for the function within parenthesis,
the function body is introduced by a left brace, variables are
declared for the function, statements implementing the function
follow, and the function is ended with a right brace.
There are some subtle differences, however. The types of parameters
and variables are not defined at compile time, but instead are typed
at runtime. Thus there is no definitions needed to distinguish
between integers, fractions, complex numbers, matrices, and so on.
Thus when declaring parameters for a function, only the name of
the parameter is needed. Thus there are never any declarations
between the function parameter list and the body of the function.
For example, the following function computes a factorial:
define factorial(n)
{
local ans;
ans = 1;
while (n > 1)
ans *= n--;
return ans;
}
If a function is very simple and just returns a value, then the
function can be defined in shortened manner by using an equals sign
in place of the left brace. In this case, the function declaration
is terminated by a newline character, and its value is the specified
expression. Statements such as 'if' are not allowed. An optional
semicolon ending the expression is allowed. As an example, the
average of two numbers could be defined as:
define average(a, b) = (a + b) / 2;
Functions can be defined which can be very complex. These can be
defined on the command line if desired, but editing of partial
functions is not possible past a single line. If an error is made
on a previous line, then the function must be finished (with probable
errors) and reentered from the beginning. Thus for complicated
functions, it is best to use an editor to create the function in a
file, and then enter the calculator and read in the file containing
the definition.
The parameters of a function can be referenced by name, as in
normal C usage, or by using the 'param' function. This function
returns the specified parameter of the function it is in, where
the parameters are numbered starting from 1. The total number
of parameters to the function is returned by using 'param(0)'.
Using this function allows you to implement varargs-like routines
which can handle any number of calling parameters. For example:
define sc()
{
local s, i;
s = 0;
for (i = 1; i <= param(0); i++)
s += param(i)^3;
return s;
}
defines a function which returns the sum of the cubes of all it's
parameters.

44
help/delete Normal file
View File

@@ -0,0 +1,44 @@
NAME
delete - delete an element from a list at a given position
SYNOPSIS
delete(lst, idx)
TYPES
lst list, &list
idx int, &int
return any
DESCRIPTION
Delete element at index idx from list lst.
The index must refer to an element in the list. That is, idx must
be in the range [0, size(lst)-1].
EXAMPLE
> lst = list(2,3,4,5)
list (4 elements, 4 nonzero):
[[0]] = 2
[[1]] = 3
[[2]] = 4
[[3]] = 5
> delete(lst, 2)
4
> print lst
list (3 elements, 3 nonzero):
[[0]] = 2
[[1]] = 3
[[2]] = 5
LIMITS
none
LIBRARY
none
SEE ALSO
append, insert, islist, list, pop, push, remove, rsearch, search, size

38
help/den Normal file
View File

@@ -0,0 +1,38 @@
NAME
den - denominator of a real number
SYNOPSIS
den(x)
TYPES
x real
return integer
DESCRIPTION
For real x, den(x) returns the denominator of x. In calc,
real values are actually rational values. Each calc real
value can be uniquely expressed as:
n / d
where:
n and d are integers
gcd(n,d) == 1
d > 0
If x = n/x, then den(x) == d.
EXAMPLE
> print den(7), den(-1.25), den(121/33)
1 4 3
LIMITS
none
LIBRARY
NUMBER *qden(NUMBER *x)
SEE ALSO
num

74
help/det Normal file
View File

@@ -0,0 +1,74 @@
NAME
det - determinant
SYNOPSIS
det(m)
TYPES
m square matrix with elements of suitable type
return zero or value of type determined by types of elements
DESCRIPTION
The matrix m has to be square, i.e. of dimension 2 with:
matmax(m,1) - matmin(m,1) == matmax(m,2) - matmin(m,2).
If the elements of m are numbers (real or complex), det(m)
returns the value of the determinant of m.
If some or all of the elements of m are not numbers, the algorithm
used to evaluate det(m) assumes the definitions of *, unary -, binary -,
being zero or nonzero, are consistent with commutative ring structure,
and if the m is larger than 2 x 2, division by nonzero elements is
consistent with integral-domain structure.
If m is a 2 x 2 matrix with elements a, b, c, d, where a tests as
nonzero, det(m) is evaluated by
det(m) = (a * d) - (c * b).
If a tests as zero, det(m) = - ((c * b) - (a * d)) is used.
If m is 3 * 3 with elements a, b, c, d, e, f, g, h, i, where a and
a * e - d * b test as nonzero, det(m) is evaluated by
det(m) = ((a * e - d * b) * (a * i - g * c)
- (a * h - g * b) * (a * f - d * c))/a.
EXAMPLE
> mat A[3,3] = {2, 3, 5, 7, 11, 13, 17, 19, 23}
> c = config("mode", "frac")
> print det(A), det(A^2), det(A^3), det(A^-1)
-78 6084 -474552 -1/78
> obj res {r}
> global md
> define res_test(a) = !ismult(a.r, md)
> define res_sub(a,b) {local obj res v = {(a.r - b.r) % md}; return v;}
> define res_mul(a,b) {local obj res v = {(a.r * b.r) % md}; return v;}
> define res_neg(a) {local obj res v = {(-a.r) % md}; return v;}
> define res(x) {local obj res v = {x % md}; return v;}
> md = 0
> mat A[2,2] = {res(2), res(3), res(5), res(7)}
> md = 5
> print det(A)
obj res {4}
> md = 6
> print det(A)
obj res {5}
Note that if A had been a 3 x 3 or larger matrix, res_div(a,b) for
non-zero b would have had to be defined (assuming at least one
division is necessary); for consistent results when md is composite,
res_div(a,b) should be defined only when b and md are relatively
prime; there is no problem when md is prime.
LIMITS
none
LIBRARY
VALUE matdet(MATRIX *m)
SEE ALSO
matdim, matmax, matmin, inverse

38
help/digit Normal file
View File

@@ -0,0 +1,38 @@
NAME
digit - digit at specified position in a decimal representation
SYNOPSIS
digit(x, y)
TYPES
x real
y integer
return integer
DESCRIPTION
By extending the digits on the left, and if necessary, the digits
on the right, by infinite strings of zeros, abs(x) may be considered
to have the decimal representation:
... d_2 d_1 d_0.d_-1 d_-2 ...
digit(x,y) then returns the digit d_y.
EXAMPLE
> x = 12.34
> print digit(x,2), digit(x,1), digit(x,0), digit(x,-1), digit(x,-2)
0 1 2 3 4
> x = 10/7
> print digit(x,1), digit(x,0), digit(x,-1), digit(x,-2), digit(x,-3)
0 1 4 2 8
LIMITS
none
LIBRARY
long qdigit(NUMBER *x, long y)
SEE ALSO
bit

27
help/digits Normal file
View File

@@ -0,0 +1,27 @@
NAME
digits - return number of digits in an integer or integer part
SYNOPSIS
digits(x)
TYPES
x real
return integer
DESCRIPTION
For real x, digits(x) returns the number of digits in the decimal
representation of int(abs(x)).
EXAMPLE
> print digits(0), digits(0.0123), digits(3.7), digits(-27), digits(-99.7)
1 1 1 2 2
LIMITS
none
LIBRARY
long qdigits(NUMBER *x)
SEE ALSO
places

38
help/dp Normal file
View File

@@ -0,0 +1,38 @@
NAME
dp - dot product of two vectors
SYNOPSIS
dp(x, y)
TYPES
x, y 1-dimensional matrices with the same number of elements
return depends on the nature of the elements of x and y
DESCRIPTION
Compute the dot product of two 1-dimensional matrices.
Let:
x = {x0, x1, ... xn}
y = {y0, y1, ... yn}
Then dp(x,y) returns the result of the calculation:
x0*y0 + x1*y1 + ... + xn*yn
EXAMPLE
> mat x[3] = {2,3,4}
> mat y[3] = {3,4,5}
> print dp(x,y)
38
LIMITS
x and y are 1-dimensional matrices
x and y have the same number of elements
LIBRARY
VALUE matdot(MATRIX *x, MATRIX *y)
SEE ALSO
cp

86
help/environment Normal file
View File

@@ -0,0 +1,86 @@
Environment variables
CALCPATH
A :-separated list of directories used to search for
scripts filenames that do not begin with /, ./ or ~.
If this variable does not exist, a compiled value
is used. Typically compiled in value is:
.:./lib:~/lib:${LIBDIR}/calc
where ${LIBDIR} is usually:
/usr/local/lib/calc
This value is used by the READ command. It is an error
if no such readable file is found.
The CALCBINDINGS file searches the CALCPATH as well.
CALCRC
On startup (unless -h or -q was given on the command
line), calc searches for files along the :-separated
$CALCRC environment variable.
If this variable does not exist, a compiled value
is used. Typically compiled in value is:
${LIBDIR}/startup:~/.calcrc
where ${LIBDIR} is usually:
/usr/local/lib/calc
Missing files along the $CALCRC path are silently ignored.
CALCBINDINGS
On startup (unless -h or -q was given on the command
line), calc reads key bindings from the filename specified
in the $CALCRC environment variable. These key bindings
are used for command line editing and the command history.
If this variable does not exist, a compiled value is used.
Typically compiled in value is:
bindings
or:
altbind (bindings where ^D means exit)
The bindings file is searched along the CALCPATH. Unlike
the READ command, a .cal extension is not added.
If the file could not be opened, or if standard input is not
a terminal, then calc will still run, but fancy command line
editing is disabled.
HOME
This value is taken to be the home directory of the
current user. It is used when files begin with '~/'.
If this variable does not exist, the home directory password
entry of the current user is used. If that information
is not available, '.' is used.
PAGER
When invoking help, this environment variable is used
to display a help file.
If this variable does not exist, a compiled value
is used. Typically compiled in value is something
such as 'more', 'less', 'pg' or 'cat'.
SHELL
When a !-command is used, the program indicated by
this environment variable is used.
If this variable does not exist, a compiled value
is used. Typically compiled in value is something
such as 'sh' is used.

34
help/epsilon Normal file
View File

@@ -0,0 +1,34 @@
NAME
epsilon - set or read the stored epsilon value
SYNOPSIS
epsilon([eps])
TYPES
eps real number greater than 0 and less than 1
return real number greater than 0 and less than 1
DESCRIPTION
Without args, epsilon() returns the current epsilon value.
With one arg, epsilon(eps) returns the current epsilon value
and sets the stored epsilon value to eps.
The stored epsilon value is used as default value for eps in
the functions appr(x, eps, rnd), sqrt(x, eps, rnd), etc.
EXAMPLE
> oldeps = epsilon(1e-6)
> print epsilon(), sqrt(2), epsilon(1e-4), sqrt(2), epsilon(oldeps)
> .000001 1.414214 .000001 1.4142 .0001
LIMITS
0 < eps < 1
LIBRARY
void setepsilon(NUMBER *eps)
NUMBER *_epsilon_
SEE ALSO
XXX - fill in

38
help/errno Normal file
View File

@@ -0,0 +1,38 @@
NAME
errno - return a system error message
SYNOPSIS
errno(errnum)
TYPES
errnum int
return string
DESCRIPTION
If a file builtin function such as fopen() encounters an error,
it will return an errno number. This function will convert this
number into a somewhat more meaningful string.
Note that errno() may return different strings on different systems.
EXAMPLE
> badfile = fopen("not_a_file", "r")
> if (!isfile(badfile)) print "error #" : badfile : ":", errno(badfile);
error #2: No such file or directory
> print errno(13)
Permission denied
> errno(31)
"Too many links"
LIMITS
none
LIBRARY
none
SEE ALSO
errno, fclose, feof, ferror, fflush, fgetc, fgetline, files, fopen,
fprintf, isfile, printf, prompt

Some files were not shown because too many files have changed in this diff Show More