#include <ansi_c.h>
/* zwofz.f -- translated by f2c (version 19970219). */
int zwofz(double w[], double z[]);

int zwofz (z, w)
double *z, *w;
{
  /* Local variables */
  static double rsqpd2 = 1.128379167095512573896158903121545171688;
  static double mxgoni = 59473682.;
  static double inogxm = 1.6814159916986475e-8;
  static double lgovfl  = 708.;
  int kapn, flag, itmp;
  double xabs, yabs, qrho, xsum, ysum, dtmp;
  int fadeeva;
  double c, h;
  int i, j, n;
  double u, v, x, y, xquad, yquad, h2, u1, u2, v1, v2, w1, qlamda;
  int nu;
  double rx, ry, sx, sy, tx, ty, uv;

  /* >>1992-10-13 ZWOFZ WVS Improve efficiency and avoid underflow. */
  /* >>1992-03-13 ZWOFZ FTK Removed implicit statements. */
  /* >>1991-08-23 ZWOFZ WV Snyder Initial adaptation to Math77 */
  /* >> HMP modified for IEEE parameters and no error print */
  /* >>> note that flag = 0 for yi > 0 */

  /*     Algorithm 680, collected algorithms from ACM. */
  /*     This work published in Transactions on Mathematical Software, */
  /*     Vol. 16, No. 1, Pp. 47. */

  /*     Modified by W. V. Snyder for inclusion in Math77: */
  /*     Reorganize checking for overflow and loss of precision so */
  /*     there are no redundant or unnecessary checks.  In the process, */
  /*     the range of applicability is expanded to the entire upper */
  /*     half-plane. */
  /*     Reorganize some calculations to be immune from overflow. */
  /*     Split loop for two outer regions into two loops -- faster in */
  /*     region. */
  /*     Use D1MACH to fetch machine characteristics. (NOT) */
  /*     Use Math77 error message processor. */

  /*  Given a complex number z = (xi,yi), this subroutine computes */
  /*  the value of the Faddeeva function w(z) = exp(-z**2)*erfc(-i*z), */
  /*  where erfc is the complex complementary error function and i */
  /*  means sqrt(-1). */
  /*  The accuracy of the algorithm for z in the 1st and 2nd quadrant */
  /*  is 14 significant digits; in the 3rd and 4th it is 13 significant */
  /*  digits outside a circular region with radius 0.126 around a zero */
  /*  of the function. */


  /*  Argument list */
  /*     Z [in]    = real and imaginary parts of z in Z(1) and Z(2) */
  /*     W [out]   = real and imaginary parts of w(z) in W(1) and W(2) */
  /*     FLAG [out] = an error flag indicating the status of the */
  /*       computation.  Type INTEGER, with values having the following */
  /*       meaning: */
  /*         0 : No error condition, */
  /*        -1 : Overflow would occur, */
  /*        +1 : There would be no significant digits in the answer. */


  /*  The routine is not underflow-protected but any variable can be */
  /*  put to zero upon underflow. */

  /*  Reference - GMP Poppe, CMJ Wijers: More efficient computation of */
  /*  the complex error-function, ACM Trans. Math. Software. */



  /*     RSQPD2 = 2/sqrt(pi) */
  /*     SQLGOV = sqrt(ln(RMAX)), where RMAX = the overflow limit for */
  /*              floating point arithmetic. */
  /*     LGOVFL  = ln(RMAX) - ln(2) */
  /*     LGUND  = ln(RMIN), where RMIN = underflow limit. */
  /*     MXGONI = the largest possible argument of sin or cos, restricted */
  /*              here to sqrt ( pi / (2*round-off-limit) ). */
  /*     INOGXM = 1 / MXGONI. */
  /*  The reason these values are needed as defined */
  /*  will be explained by comments in the code. */

  xabs = fabs(z[0]);
  yabs = fabs(z[1]);
  x = xabs / 6.3;
  y = yabs / 4.4;
  
  if (x > y) {
    dtmp = y / x;
    qrho = x * sqrt(dtmp * dtmp + 1.);
  } else if (y == 0.) {
    qrho = 0.;
  } else {
    dtmp = x / y;
    qrho = y * sqrt(dtmp * dtmp + 1.);
  }

  fadeeva = (qrho < 0.292);
  if (fadeeva) {

    /*  qrho .lt. 0.292, equivalently qrho**2 .lt. 0.085264: the Fadeeva */
    /*  function is evaluated using a power-series (Abramowitz and */
    /*  Stegun, equation (7.1.5), p.297). */
    /*  N is the minimum number of terms needed to obtain the required */
    /*  accuracy. */
    /*  We know xquad and exp(-xquad) and yqyad and sin(yquad) won't */
    /*  cause any trouble here, because qrho .lt. 1. */
    xquad = (xabs - yabs) * (xabs + yabs);
    yquad = 2. * xabs * yabs;
    n = (int) ((1. - 0.85 * y) * 72. * qrho + 6.5);
    j = (n << 1) + 1;
    xsum = rsqpd2 / j;
    ysum = 0.;
    for (i = n; i > 0; --i) {
      j -= 2;
      w1 = (xsum * xquad - ysum * yquad) / i;
      ysum = (xsum * yquad + ysum * xquad) / i;
      xsum = w1 + rsqpd2 / j;
    }
    u1 = 1. - (xsum * yabs + ysum * xabs);
    v1 = xsum * xabs - ysum * yabs;
    w1 = exp(-xquad);
    u2 = w1 * cos(yquad);
    v2 = -w1 * sin(yquad);
    u = u1 * u2 - v1 * v2;
    v = u1 * v2 + v1 * u2;
  } else {
    rx = 0.;
    ry = 0.;
    sx = 0.;
    sy = 0.;

    /*  The loops in both branches of the IF block below are similar. */
    /*  They could be combined to reduce space, but extra tests and */
    /*  unnecessary computation would be needed. */

    if (qrho < 1.) {
      /*  0.292 < qrho < 1.0: w(z) is evaluated by a truncated */
      /*  Taylor expansion, where the Laplace continued fraction */
      /*  is used to calculate the derivatives of w(z). */
      /*  KAPN is the minimum number of terms in the Taylor expansion */
      /*       needed to obtain the required accuracy. */
      /*  NU is the minimum number of terms of the continued fraction */
      /*     needed to calculate the derivatives with the required */
      /*     accuracy. */
      /*  x*x + y*y is more accurate than qrho*qrho here: */
      c = (1. - y) * sqrt(1. - x * x - y * y);
      h = 1.88 * c;  h2 = 2. * h;
      nu = (int) (26. * c + 17.5);
      kapn = (int) (34. * c + 8.5);
      /*  Select kapn so qlamda doesn't underflow.  Small kapn is good */
      /*         (when possible) for performance also. */
      if (h2 < 0.25) {
        itmp = (int) (-lgovfl / log(h2)) + 1;
        if (itmp < kapn) kapn = itmp;
      }
      qlamda = pow(h2, (double) (kapn - 1));
      /*  0 < qlamda < 3.76**41 < 3.85d23. */
      for (n = nu; n > kapn; --n) {
        tx = yabs + h + n * rx;
        ty = xabs - n * ry;
        /* No overflow because tx*rx + ty*ry = 1 and 0.292 < qrho < 1: */
        c = 0.5 / (tx * tx + ty * ty);
        rx = tx * c;
        ry = ty * c;
      }
      for (n = kapn; n > 0; --n) {
        tx = yabs + h + n * rx;
        ty = xabs - n * ry;
        /*  No overflow because tx*rx + ty*ry = 1 and 0.292 < qrho < 1: */
        c = 0.5 / (tx * tx + ty * ty);
        rx = tx * c;
        ry = ty * c;
        tx = qlamda + sx;
        sx = rx * tx - ry * sy;
        sy = ry * tx + rx * sy;
        qlamda /= h2;
      }
      u = sx * rsqpd2;
      v = sy * rsqpd2;
    } else {
      /*   qrho >= 1.: w(z) is evaluated using the Laplace continued */
      /*   fraction. */
      /*   NU is the minimum number of terms needed to obtain the */
      /*       required accuracy. */
      nu = (int) (1442. / (26. * qrho + 77.) + 4.5);
      for (n = nu; n > 0; --n) {
        tx = yabs + n * rx;
        ty = xabs - n * ry;
        if (tx > fabs(ty)) break;
        /*  rx = 0.5*tx/(tx**2+ty**2) and ry = 0.5*ty/(tx**2+ty**2), */
        /*  computed without overflow.  Underflow is OK. */
        c = tx / ty;
        ry = 0.5 / (ty * (c * c + 1.));
        rx = ry * c;
      }
      while (n > 0){
        /*  Once tx>abs(ty), it stays that way. */
        /*  rx = 0.5*tx/(tx**2+ty**2) and ry = 0.5*ty/(tx**2+ty**2), */
        /*  computed without overflow.  Underflow is OK. */
        c = ty / tx;
        rx = 0.5 / (tx * (c * c + 1.));
        ry = rx * c;
        if (--n == 0) break;
        tx = yabs + n * rx;
        ty = xabs - n * ry;
      }
      u = rx * rsqpd2;
      v = ry * rsqpd2;
    }
    if (yabs == 0.) {
      dtmp = xabs * xabs;
      if (dtmp > lgovfl) {
        u = 0.;
      } else {
        u = exp(-dtmp);
      }
    }
  }

  /*     Evaluation of w(z) in the other quadrants. */
  flag = 0;
  if (z[1] < 0.) { /* y is negative */
    if (fadeeva) {
      u = 2. * u2 - u;
      v = 2. * v2 - v;
    } else {
      /*  Check whether sin(2*xabs*yabs) has any precision, without */
      /*  allowing 2*xabs*yabs to overflow. */
      if (yabs > xabs) {
        if (yabs > inogxm) {
          /*  The following protects 2*exp(-z**2) against overflow. */
          if (lgovfl / yabs < yabs - xabs * (xabs / yabs)) 
            flag = -1;
        }else{
          w1 = 2. * exp((yabs - xabs) * (yabs + xabs));
          uv = fabs(u); dtmp = fabs(v);
          if (dtmp < uv) uv = dtmp; /* uv = min (abs(u), abs(v)) */
          dtmp = xabs * yabs;
          if (w1 < uv) dtmp *= (w1 / uv);
          if (dtmp > mxgoni) flag = 1;
        }
      } else if (xabs > inogxm) {
        if (lgovfl / xabs < xabs - yabs * (yabs / xabs)) {
          /*   (yabs-xabs)*(yabs+xabs) might have overflowed, but in that */
          /*   case, exp((yabs-xabs)*(yabs+xabs)) would underflow. */
          u = -u; v = -v; flag = 2;
        }else{
          /* (yabs-xabs)*(yabs+xabs) can't overflow here. */
          w1 = 2. * exp((yabs - xabs) * (yabs + xabs));
          uv = fabs(u); dtmp = fabs(v);
        }
		if (abs(u) < abs(v)){ uv = abs(u);} else {uv = abs(v);}
        if (dtmp < uv) uv = dtmp; /* uv = min (abs(u), abs(v)) */
        dtmp = xabs * yabs;
        if (w1 < uv) dtmp *= (w1 / uv);
        if (dtmp > mxgoni) flag = 1;
      }
    }
    if (flag == 0){
      yquad = 2. * xabs * yabs;
      u =  w1 * cos(yquad) - u;
      v = -w1 * sin(yquad) - v;
    }
    if (flag == 2) flag = 0;
  }
  if (flag) {
    w[0] = exp(lgovfl);
    w[1] = w[0];
  }else{
    w[0] = u;
    if (z[0] < 0.)  v = -v; 
    w[1] = v;
  }
  return flag;
} /* zwofz */
