home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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));
- }
-