#include "xlisp.h"
#include "xlstat.h"

#define twopi 6.283195307179587
#define con (twopi / 2.0) * 10.0e-10

double bivnor P3C(double, ah, double, ak, double, r)
{
  /*
    based on alg 4628 comm. acm oct 73
    gives the probability that a bivariate normal exceeds (ah,ak).
    gh and gk are .5 times the right tail areas of ah, ak under a n(0,1)

    Tranlated from FORTRAN to ratfor using struct; from ratfor to C by hand.
  */
  double a2, ap, b, cn, conex, ex, g2, gh, gk, gw, h2, h4, rr, s1, s2, 
    sgn, sn, sp, sqr, t, temp, w2, wh, wk;
  int is;

  temp = -ah;
  normbase(&temp, &gh);
  gh = gh / 2.0;
  temp = -ak;
  normbase(&temp, &gk);
  gk = gk / 2.0;

  b = 0;

  if (r==0)
    b = 4*gh*gk;
  else {
    rr = 1-r*r;
    if (rr<0)
      return(-1.0);
    if (rr!=0) {
      sqr = sqrt(rr);
      if (ah!=0) {
	b = gh;
	if (ah*ak<0)
	  b = b-.5;
	else if (ah*ak==0)
	  goto label10;
      }
      else if (ak==0) {
	b = atan(r/sqr)/twopi+.25;
	goto label50;
      }
      b = b+gk;
      if (ah==0)
	goto label20;
    label10:  
      wh = -ah;
      wk = (ak/ah-r)/sqr;
      gw = 2*gh;
      is = -1;
      goto label30;
    label20:  
      do {
	wh = -ak;
	wk = (ah/ak-r)/sqr;
	gw = 2*gk;
	is = 1;
      label30:  
	sgn = -1;
	t = 0;
	if (wk!=0) {
	  if (fabs(wk)>=1)
	    if (fabs(wk)==1) {
	      t = wk*gw*(1-gw)/2;
	      goto label40;
	    }
	    else {
	      sgn = -sgn;
	      wh = wh*wk;
	      normbase(&wh, &g2);
	      wk = 1/wk;
	      if (wk<0)
		b = b+.5;
	      b = b-(gw+g2)/2+gw*g2;
	    }
	  h2 = wh*wh;
	  a2 = wk*wk;
	  h4 = h2*.5;
	  ex = 0;
	  if (h4<150.0)
	    ex = exp(-h4);
	  w2 = h4*ex;
	  ap = 1;
	  s2 = ap-ex;
	  sp = ap;
	  s1 = 0;
	  sn = s1;
	  conex = fabs(con/wk);
	  do {
	    cn = ap*s2/(sn+sp);
	    s1 = s1+cn;
	    if (fabs(cn)<=conex)
	      break;
	    sn = sp;
	    sp = sp+1;
	    s2 = s2-w2;
	    w2 = w2*h4/sp;
	    ap = -ap*a2;
	  } while (1);
	  t = (atan(wk)-wk*s1)/twopi;
	label40:  
	  b = b+sgn*t;
	}
	if (is>=0)
	  break;
      } while(ak!=0);
    }
    else if (r>=0)
      if (ah>=ak)
	b = 2*gh;
      else
	b = 2*gk;
    else if (ah+ak<0)
      b = 2*(gh+gk)-1;
  }
 label50: 
  if (b<0)
    b = 0;
  if (b>1)
    b = 1;

  return(b);
}


syntax highlighted by Code2HTML, v. 0.9.1