home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
amiga
/
misc
/
icalc.lzh
/
icalc
/
src
/
cmath.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-26
|
7KB
|
387 lines
/*
* icalc - complex-expression parser
*
* Math routines for complex-number expression parser.
* In the routines, rv is variable holding 'return value'.
*
* (C) Martin W Scott, 1991.
*/
#include <math.h>
#include "complex.h"
#include "constant.h"
#define NOERRCHECK /* domain checking doesn't work when using */
/* IEEE libraries... */
#ifdef NOERRCHECK
#define Log(x) log(x)
#endif
#define Zero(x) ((x) == 0.0) /* may add epsilons at a later date... */
Complex Re(z) /* real part of complex number */
Complex z;
{
z.imag = 0.0;
return z;
}
Complex Im(z) /* imaginary part of complex number */
Complex z;
{
z.real = z.imag;
z.imag = 0.0;
return z;
}
#define realarg(z) atan2((z).imag,(z).real) /* macro arg */
#define realnorm(z) ((z).real*(z).real+(z).imag*(z).imag) /* real norm */
static double sgn(x) /* sign of x */
double x;
{
if (x > 0.0) return 1.0;
else if (x < 0.0) return -1.0;
else return 0.0;
}
Complex arg(z) /* argument of complex number, in range (-PI,PI] */
Complex z;
{
z.real = realarg(z);
z.imag = 0.0;
return z;
}
Complex norm(z) /* norm of a complex number */
Complex z;
{
z.real = sqr(z.real) + sqr(z.imag);
z.imag = 0.0;
return z;
}
Complex cabs(z) /* absolute value of a complex number */
Complex z;
{
z.real = sqrt(realnorm(z));
z.imag = 0.0;
return z;
}
Complex cadd(w,z) /* complex addition */
Complex w,z;
{
w.real = w.real + z.real;
w.imag = w.imag + z.imag;
return w;
}
Complex csub(w,z) /* complex subtraction */
Complex w,z;
{
w.real = w.real - z.real;
w.imag = w.imag - z.imag;
return w;
}
Complex cmul(w,z) /* complex multiplication */
Complex w,z;
{
Complex rv;
rv.real = w.real*z.real - w.imag*z.imag;
rv.imag = w.real*z.imag + w.imag*z.real;
return rv;
}
Complex cdiv(w,z) /* complex division */
Complex w,z;
{
Complex rv;
double temp = sqr(z.real)+sqr(z.imag);
if (Zero(temp))
execerror("division by zero", NULL);
rv.real = (w.real*z.real + w.imag*z.imag)/temp;
rv.imag = (w.imag*z.real - w.real*z.imag)/temp;
return rv;
}
Complex cneg(z) /* complex negation */
Complex z;
{
z.real = -z.real;
z.imag = -z.imag;
return z;
}
Complex csqr(z) /* complex square, w^2 */
Complex z;
{
Complex rv;
if (Zero(z.imag)) /* small optimisation for reals */
{
z.real *= z.real;
return z;
}
rv.real = sqr(z.real) - sqr(z.imag);
rv.imag = 2*z.real*z.imag;
return rv;
}
Complex csqrt(z) /* complex square-root */
Complex z;
{
if (Zero(z.imag)) /* real */
{
if (z.real >= 0.0)
z.real = sqrt(z.real);
else
{
z.imag = sqrt(-z.real);
z.real = 0.0;
}
}
else /* complex */
{
double absval, temp;
absval = sqrt(realnorm(z));
temp = sqrt((absval + z.real)/2.0);
z.imag = sgn(z.imag)*sqrt((absval - z.real)/2.0);
z.real = temp;
}
return z;
}
Complex conj(z) /* conjugate of w */
Complex z;
{
z.imag = -z.imag;
return z;
}
Complex cexp(z) /* complex exponential function e^z */
Complex z;
{
double temp = exp(z.real);
if (Zero(z.imag)) /* small optimisation for reals */
z.real = temp;
else
{
z.real = temp*cos(z.imag);
z.imag = temp*sin(z.imag);
}
return z;
}
Complex clog(z) /* complex natural logarithm */
Complex z;
{
Complex rv;
if (Zero(z.imag) && Zero(z.real))
execerror("domain error in logarithm", NULL);
rv.real = Log(realnorm(z))*0.5;
rv.imag = realarg(z);
return rv;
}
Complex cpow(w,z) /* complex exponential, w^z */
Complex w,z;
{
return cexp(cmul(z,clog(w)));
}
Complex csin(z) /* complex sine */
Complex z;
{
if (Zero(z.imag)) /* small optimisation for reals */
{
z.real = sin(z.real);
return z;
}
else
{
Complex rv;
rv.real = sin(z.real)*cosh(z.imag);
rv.imag = cos(z.real)*sinh(z.imag);
return rv;
}
}
Complex ccos(z) /* complex cosine */
Complex z;
{
if (Zero(z.imag)) /* small optimisation for reals */
{
z.real = cos(z.real);
return z;
}
else
{
Complex rv;
rv.real = cos(z.real)*cosh(z.imag);
rv.imag = -(sin(z.real)*sinh(z.imag));
return rv;
}
}
Complex ctan(z) /* complex tangent */
Complex z;
{
if (Zero(z.imag)) /* small optimisation for reals */
{
z.real = tan(z.real);
return z;
}
else
return cdiv(csin(z),ccos(z));
}
Complex casin(z) /* complex arcsine - lazy version */
Complex z;
{
/* asin z = -ilog(iz + sqrt(1-z^2)) */
/* PVR taken as follows:
* u+iv = acos(z), then
* -PI/2 <= u <= PI/2 when v >= 0,
* -PI/2 < u < PI/2 when v < 0.
* This seems most logical, though conventions vary...
*/
double multiplier = 1.0; /* to get standard definition into PVR */
if (Zero(z.imag))
{
if (abs(z.real) <= 1.0) /* real method */
{
z.real = asin(z.real);
return z;
}
multiplier = -sgn(z.real);
/* to get into PVR */
}
z = cmul(minuseye,clog(cadd(cmul(eye,z),csqrt(csub(one,csqr(z))))));
z.imag *= multiplier;
return z;
}
Complex cacos(z) /* complex arccosine */
Complex z; /* if someone knows a neater way, tell me! */
{
/* acos z = -ilog(z + sqrt(z^2-1)), into PVR */
/* PVR taken as follows:
* u+iv = acos(z), then
* 0 <= u <= PI when v >= 0,
* 0 < u < PI when v < 0.
* This seems most logical, though conventions vary...
*/
double multiplier; /* to get standard definition into PVR */
if (Zero(z.imag)) /* on real axis */
{
if (abs(z.real) <= 1.0) /* real-valued */
{
z.real = acos(z.real);
return z;
}
multiplier = -sgn(z.real);
/* because csqrt returns prinipal value */
/* (1,inf) -> (0,inf)i */
/* (-inf,1) -> PI+(0,inf)i */
}
else if (!Zero(z.real)) multiplier = sgn(z.real)*sgn(z.imag);
else multiplier = 1.0;
/* again to get in PVR */
z = cmul(minuseye,clog(cadd(z,csqrt(csub(csqr(z),one)))));
z.real *= multiplier;
z.imag *= multiplier;
return z;
}
Complex catan(z) /* complex arctangent - not so lazy version */
Complex z;
{
/* easier than other two - no ambiguity about which root to take
* (there aren't any) and no boundaries to worry about...
*
* PVR as follows: u+iv = atan(z), then
* -PI/2 < u < PI/2
* -inf < v < inf
*/
if (Zero(z.imag)) /* small optimisation for reals */
z.real = atan(z.real);
else
{
Complex ctemp;
double temp = realnorm(z);
ctemp.real = ctemp.imag = 1.0 / (1.0 + temp - 2.0 * z.imag);
ctemp.real *= 1.0 - temp;
ctemp.imag *= -2.0*z.real;
ctemp = clog(ctemp);
z.real = -0.5*ctemp.imag;
z.imag = 0.5*ctemp.real;
}
return z;
}
Complex csinh(z) /* complex hyperbolic sine */
Complex z;
{
Complex rv;
rv.real = cos(z.imag)*sinh(z.real);
rv.imag = sin(z.imag)*cosh(z.real);
return rv;
}
Complex ccosh(z) /* complex hyperbolic cosine */
Complex z;
{
Complex rv;
rv.real = cos(z.imag)*cosh(z.real);
rv.imag = sin(z.imag)*sinh(z.real);
return rv;
}
Complex ctanh(z) /* complex tangent */
Complex z;
{
return cdiv(csinh(z),ccosh(z));
}