Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/deval/
Upload File :
Current File : /usr/home/beeson/MathXpert/deval/dcomplex.c

/* complex arithmetic and elementary transcendental functions */
/* M. Beeson, for Mathpert; first part adapted from Numerical Recipes
   Original date 7.11.91
   Code last modified 4.23.93
   11.17.93 added math.h
   7.11.94 added EXPORTs
  10.17.94 modified to check for overflow
  2.6.97  Corrected CAtan--there is an error in Abramowitz and Stegun!
  9.18.97 MEXPORT_DEVAL
  1.29.98 last modified
  4.7.06 changed hypot to _hypot
  5.4.13  put in conditional compilation for hypot and _hypot
          added stdlib.h
*/

#include <math.h>
#include <stdlib.h>  // for abs in C99 

#include "terms.h"
#include "dcomplex.h"
#include "special.h"
#include "deval.h"

#ifdef XCODE
#define _hypot hypot
#endif 

#define MAXEXP  400  /* maximum power of 2 allowed in quotient */

dcomplex Cplus(dcomplex a,dcomplex b)
 /* the name 'cadd' is used in arith.c for something else */
{ dcomplex c;
  c.r=a.r+b.r;
  c.i=a.i+b.i;
  return c;
}

dcomplex Csub(dcomplex a,dcomplex b)
{ dcomplex c;
  c.r=a.r-b.r;
  c.i=a.i-b.i;
  return c;
}

dcomplex Cmul(dcomplex a,dcomplex b)
{ dcomplex c;
  c.r=a.r*b.r-a.i*b.i;
  c.i=a.i*b.r+a.r*b.i;
  return c;
}

dcomplex Cdiv(dcomplex a,dcomplex b)
{ dcomplex c;
  int checknum, checkden;
  double r,num,den;
  if (fabs(b.r) >= fabs(b.i))
     { r=b.i/b.r;
       den=b.r+r*b.i;
       num = a.r + r*a.i;
       /* Check for overflow before dividing */
       if(den == 0.0)
          { /* in this case frexp won't be large so must
               catch this case separately */
            c.r = BADVAL;
            c.i = 0;
            return c;
          }
       frexp(den,&checkden);
       frexp(num,&checknum);
       if(abs(checkden-checknum) > MAXEXP)
          { c.r = BADVAL;
            c.i = 0;
            return c;
          }
       c.r = num/den;
       num = a.i-r*a.r;
       frexp(num,&checknum);
       if(abs(checkden-checknum) > MAXEXP)
          { c.r = BADVAL;
            c.i = 0;
            return c;
          }
       c.i = num/den;
     }
  else
     { r=b.r/b.i;
       den=b.i+r*b.r;
       num = a.r*r + a.i;
      /* Check for overflow before dividing */
       frexp(den,&checkden);
       frexp(num,&checknum);
       if(abs(checkden-checknum) > MAXEXP)
          { c.r = BADVAL;
            c.i = 0;
            return c;
          }
       c.r = num/den;
       num = a.i*r-a.r;
       frexp(num,&checknum);
       if(abs(checkden-checknum) > MAXEXP)
          { c.r = BADVAL;
            c.i = 0;
            return c;
          }
       c.i = num/den;
     }
  return c;
}

double Cabs(dcomplex z)
{ double x,y,ans,temp;
  x=fabs(z.r);
  y=fabs(z.i);
  if (x == 0.0)
     ans=y;
  else if (y == 0.0)
     ans=x;
  else if (x > y)
     { temp=y/x;
       ans=x*sqrt(1.0+temp*temp);
     }
  else
     { temp=x/y;
       ans=y*sqrt(1.0+temp*temp);
     }
  return ans;
}

dcomplex Csqrt(dcomplex z)
{ dcomplex c;
  double x,y,w,r;
  if ((z.r == 0.0) && (z.i == 0.0))
     { c.r=0.0;
       c.i=0.0;
       return c;
     }
  else
     { x=fabs(z.r);
       y=fabs(z.i);
       if (x >= y)
          { r=y/x;
            w=sqrt(x)*sqrt(0.5*(1.0+sqrt(1.0+r*r)));
          }
       else
          { r=x/y;
            w=sqrt(y)*sqrt(0.5*(r+sqrt(1.0+r*r)));
          }
       if (z.r >= 0.0)
          { c.r=w;
            c.i=z.i/(2.0*w);
          }
       else
          { c.i=(z.i >= 0) ? w : -w;
            c.r=z.i/(2.0*c.i);
          }
      return c;
    }
}

dcomplex RCmul(double x,dcomplex a)
{ dcomplex c;
  c.r=x*a.r;
  c.i=x*a.i;
  return c;
}

dcomplex make_dcomplex(double x, double y)
{ dcomplex c;
  c.r = x;
  c.i = y;
  return c;
}

/*_____End of the part adapted from Numerical Recipes ______________________*/

dcomplex Cneg(dcomplex x)
/* the name 'cnegate' is used in arith.c for something else */
{  dcomplex c;
   c.r = x.r == 0.0 ? 0.0 : -x.r;   /* don't create -0.0 */
   c.i = x.i == 0.0 ? 0.0 : -x.i;
   return c;
}

dcomplex Cexp(dcomplex z)
/* e^(x+iy) = e^x  cos y + i e^x sin y */
{ dcomplex c;
  double x = z.r;
  double y = z.i;
  double r = exp(x);
  c.r = r * cos(y);
  c.i = r * sin(y);
  return c;
}

double  Carg(dcomplex z)
{ return atan2(z.i,z.r);
}

dcomplex Crecip(dcomplex z)
{ return Cdiv(make_dcomplex(1.0,0.0),z);
}

dcomplex Cln(dcomplex z)
/*  ln(z) = ln(Cabs(z) + i Carg(z) */
{ dcomplex c;
  c.r = log(Cabs(z));
  c.i = Carg(z);
  return c;
}

dcomplex Cpower(dcomplex u, dcomplex v)
/* u^v = e^(v ln u) = */
/* Does not check for 0^0 */
{ if(u.r == 0.0 && u.i == 0.0)
     return make_dcomplex(0.0,0.0);
  if(v.r == 0.0 && v.i == 0.0)
     return make_dcomplex(1.0,0.0);
  return Cexp(Cmul(v,Cln(u)));
}

dcomplex Croot(dcomplex n, dcomplex z)
/* compute root(n,z) */
{ return Cpower(z, Crecip(n));
}

dcomplex Ccos(dcomplex z)
{ dcomplex c,u,v;
  u.r = - z.i;
  u.i = z.r;   /* u =  iz */
  v.r = z.i;
  v.i = -z.r;  /* v = -iz */
  c = Cplus(Cexp(u),Cexp(v));
  c.r *= 0.5;
  c.i *= 0.5;
  return c;
}

dcomplex Csin(dcomplex z)
{ dcomplex c,u,v;
  double temp;
  u.r = - z.i;
  u.i = z.r;   /* u =  iz */
  v.r = z.i;
  v.i = -z.r;  /* v = -iz */
  c = Csub(Cexp(u),Cexp(v));
  c.r *= 0.5;
  c.i *= 0.5;
  temp = c.i;
  c.i = - c.r;
  c.r = temp;    /* divide c by i, that is, multiply by -i */
  return c;
}

void Ctrig(dcomplex z, dcomplex *cc, dcomplex *ss)
/* return indirectly cos z and sin z simultaneously */
{ dcomplex c,u,v,expu,expv;
  double temp;
  dcomplex ctemp;
  u.r = - z.i;
  u.i = z.r;   /* u =  iz */
  v.r = z.i;
  v.i = -z.r;  /* v = -iz */
  expu = Cexp(u);
  expv = Cexp(v);
  c = Csub(expu,expv);
  c.r *= 0.5;
  c.i *= 0.5;
  temp = c.i;
  ss->i = - c.r;
  ss->r = temp;    /* divide c by i, that is, multiply by -i */
  /* Now compute cos z */
  ctemp = Cplus(expu,expv);
  cc->i = 0.5 * ctemp.i;
  cc->r = 0.5 * ctemp.r;
}


dcomplex Ctan(dcomplex z)
{ return Cdiv(Csin(z),Ccos(z));
}

dcomplex Csec(dcomplex z)
{ return Crecip(Ccos(z));
}

dcomplex Ccsc(dcomplex z)
{ return Crecip(Csin(z));
}

dcomplex Ccot(dcomplex z)
{ return Cdiv(Ccos(z),Csin(z));   /* not 1/tan as that can't give zero */
}

dcomplex Ccosh(dcomplex z)
{ return RCmul(0.5, Cplus(Cexp(z),Cexp(Cneg(z))));
}

dcomplex Csinh(dcomplex z)
{ return RCmul(0.5, Csub(Cexp(z),Cexp(Cneg(z))));
}

dcomplex Ctanh(dcomplex z)
{ return Cdiv(Csinh(z),Ccosh(z));
}


/* The following formulas for complex inverse trig functions
are taken from pages 80-81 of Handbook of Mathematical Functions,
published by Dover.  I guess not too many mathematicians know these!
*/

dcomplex Cacos(dcomplex z)
/* real part returned in same range as acos */
{ double alpha,beta,x,y,u,v;
  dcomplex c;
  x = z.r;
  y = z.i;
  u = 0.5 * _hypot(x+1,y);
  v = 0.5 * _hypot(x-1,y);
  alpha = u + v;
  beta =  u - v;
  c.r = acos(beta);
  c.i = -log(alpha + _hypot(alpha, sqrt(alpha * alpha -1.0)));
  return c;
}

dcomplex Casin(dcomplex z)
/* real part returned in same range as asin */
{ double alpha,beta,x,y,u,v;
  dcomplex c;
  x = z.r;
  y = z.i;
  u = 0.5 * _hypot(x+1,y);
  v = 0.5 * _hypot(x-1,y);
  alpha = u + v;
  beta =  u - v;
  c.r = asin(beta);
  c.i = log(alpha + _hypot(alpha, sqrt(alpha * alpha -1.0)));
  return c;
}

dcomplex Catan(dcomplex z)
/* real part returned in same range as atan  */
/* See Abramowitz and Stegun 4.4.39, page 81 */
/* But I think Abramowitz and Stegun have it wrong;
   it should be k pi/2  where they have k pi.
   Consider the case y = 0.  Then the identity boils down to
   arctan x = (1/2) arctan(2x/(1-x^2) + k pi/2,
   not k pi as A & S would have it, e.g. when x = 2 we have
   arctan 2 = (1/2) arctan(4/(-3)) + pi/2 = pi_term/2 - (1/2)arctan(4/3) = 1.107
*/
{ dcomplex c;
  double x,y,u,num,den,t;
  x = z.r;
  y = z.i;
  u = x*x;
  if(y == 0.0)
    { c.r = atan(x);
      c.i = 0.0;
      return c;
    }
  num = u + (y+1)*(y+1);
  den = u + (y-1)*(y-1);
  c.i = 0.25 * log(num/den);
  t = 1-u-y*y;
  if(fabs(t) < VERYSMALL) /* assume it was meant to be zero */
     c.r = PI_DECIMAL/4.0;
  else if(t > 0.0)
     c.r = 0.5 * atan(2*x/t);
  else
     c.r = 0.5 * (atan(2*x/t) + PI_DECIMAL);
  return c;
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists