xref: /plan9-contrib/sys/src/cmd/map/libmap/elco2.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1*59cc4ca5SDavid du Colombier #include <u.h>
2*59cc4ca5SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "map.h"
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier /* elliptic integral routine, R.Bulirsch,
63e12c5d1SDavid du Colombier  *	Numerische Mathematik 7(1965) 78-90
73e12c5d1SDavid du Colombier  *	calculate integral from 0 to x+iy of
83e12c5d1SDavid du Colombier  *	(a+b*t^2)/((1+t^2)*sqrt((1+t^2)*(1+kc^2*t^2)))
93e12c5d1SDavid du Colombier  *	yields about D valid figures, where CC=10e-D
103e12c5d1SDavid du Colombier  *	for a*b>=0, except at branchpoints x=0,y=+-i,+-i/kc;
113e12c5d1SDavid du Colombier  *	there the accuracy may be reduced.
123e12c5d1SDavid du Colombier  *	fails for kc=0 or x<0
133e12c5d1SDavid du Colombier  *	return(1) for success, return(0) for fail
143e12c5d1SDavid du Colombier  *
153e12c5d1SDavid du Colombier  *	special case a=b=1 is equivalent to
163e12c5d1SDavid du Colombier  *	standard elliptic integral of first kind
173e12c5d1SDavid du Colombier  *	from 0 to atan(x+iy) of
183e12c5d1SDavid du Colombier  *	1/sqrt(1-k^2*(sin(t))^2) where k^2=1-kc^2
193e12c5d1SDavid du Colombier */
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier #define ROOTINF 10.e18
223e12c5d1SDavid du Colombier #define CC 1.e-6
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier int
elco2(double x,double y,double kc,double a,double b,double * u,double * v)25219b2ee8SDavid du Colombier elco2(double x, double y, double kc, double a, double b, double *u, double *v)
263e12c5d1SDavid du Colombier {
273e12c5d1SDavid du Colombier 	double c,d,dn1,dn2,e,e1,e2,f,f1,f2,h,k,m,m1,m2,sy;
283e12c5d1SDavid du Colombier 	double d1[13],d2[13];
293e12c5d1SDavid du Colombier 	int i,l;
303e12c5d1SDavid du Colombier 	if(kc==0||x<0)
313e12c5d1SDavid du Colombier 		return(0);
323e12c5d1SDavid du Colombier 	sy = y>0? 1: y==0? 0: -1;
333e12c5d1SDavid du Colombier 	y = fabs(y);
343e12c5d1SDavid du Colombier 	csq(x,y,&c,&e2);
353e12c5d1SDavid du Colombier 	d = kc*kc;
363e12c5d1SDavid du Colombier 	k = 1-d;
373e12c5d1SDavid du Colombier 	e1 = 1+c;
383e12c5d1SDavid du Colombier 	cdiv2(1+d*c,d*e2,e1,e2,&f1,&f2);
393e12c5d1SDavid du Colombier 	f2 = -k*x*y*2/f2;
403e12c5d1SDavid du Colombier 	csqr(f1,f2,&dn1,&dn2);
413e12c5d1SDavid du Colombier 	if(f1<0) {
423e12c5d1SDavid du Colombier 		f1 = dn1;
433e12c5d1SDavid du Colombier 		dn1 = -dn2;
443e12c5d1SDavid du Colombier 		dn2 = -f1;
453e12c5d1SDavid du Colombier 	}
463e12c5d1SDavid du Colombier 	if(k<0) {
473e12c5d1SDavid du Colombier 		dn1 = fabs(dn1);
483e12c5d1SDavid du Colombier 		dn2 = fabs(dn2);
493e12c5d1SDavid du Colombier 	}
503e12c5d1SDavid du Colombier 	c = 1+dn1;
513e12c5d1SDavid du Colombier 	cmul(e1,e2,c,dn2,&f1,&f2);
523e12c5d1SDavid du Colombier 	cdiv(x,y,f1,f2,&d1[0],&d2[0]);
533e12c5d1SDavid du Colombier 	h = a-b;
543e12c5d1SDavid du Colombier 	d = f = m = 1;
553e12c5d1SDavid du Colombier 	kc = fabs(kc);
563e12c5d1SDavid du Colombier 	e = a;
573e12c5d1SDavid du Colombier 	a += b;
583e12c5d1SDavid du Colombier 	l = 4;
593e12c5d1SDavid du Colombier 	for(i=1;;i++) {
603e12c5d1SDavid du Colombier 		m1 = (kc+m)/2;
613e12c5d1SDavid du Colombier 		m2 = m1*m1;
623e12c5d1SDavid du Colombier 		k *= f/(m2*4);
633e12c5d1SDavid du Colombier 		b += e*kc;
643e12c5d1SDavid du Colombier 		e = a;
653e12c5d1SDavid du Colombier 		cdiv2(kc+m*dn1,m*dn2,c,dn2,&f1,&f2);
663e12c5d1SDavid du Colombier 		csqr(f1/m1,k*dn2*2/f2,&dn1,&dn2);
673e12c5d1SDavid du Colombier 		cmul(dn1,dn2,x,y,&f1,&f2);
683e12c5d1SDavid du Colombier 		x = fabs(f1);
693e12c5d1SDavid du Colombier 		y = fabs(f2);
703e12c5d1SDavid du Colombier 		a += b/m1;
713e12c5d1SDavid du Colombier 		l *= 2;
723e12c5d1SDavid du Colombier 		c = 1 +dn1;
733e12c5d1SDavid du Colombier 		d *= k/2;
743e12c5d1SDavid du Colombier 		cmul(x,y,x,y,&e1,&e2);
753e12c5d1SDavid du Colombier 		k *= k;
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier 		cmul(c,dn2,1+e1*m2,e2*m2,&f1,&f2);
783e12c5d1SDavid du Colombier 		cdiv(d*x,d*y,f1,f2,&d1[i],&d2[i]);
793e12c5d1SDavid du Colombier 		if(k<=CC)
803e12c5d1SDavid du Colombier 			break;
813e12c5d1SDavid du Colombier 		kc = sqrt(m*kc);
823e12c5d1SDavid du Colombier 		f = m2;
833e12c5d1SDavid du Colombier 		m = m1;
843e12c5d1SDavid du Colombier 	}
853e12c5d1SDavid du Colombier 	f1 = f2 = 0;
863e12c5d1SDavid du Colombier 	for(;i>=0;i--) {
873e12c5d1SDavid du Colombier 		f1 += d1[i];
883e12c5d1SDavid du Colombier 		f2 += d2[i];
893e12c5d1SDavid du Colombier 	}
903e12c5d1SDavid du Colombier 	x *= m1;
913e12c5d1SDavid du Colombier 	y *= m1;
923e12c5d1SDavid du Colombier 	cdiv2(1-y,x,1+y,-x,&e1,&e2);
933e12c5d1SDavid du Colombier 	e2 = x*2/e2;
943e12c5d1SDavid du Colombier 	d = a/(m1*l);
953e12c5d1SDavid du Colombier 	*u = atan2(e2,e1);
963e12c5d1SDavid du Colombier 	if(*u<0)
973e12c5d1SDavid du Colombier 		*u += PI;
983e12c5d1SDavid du Colombier 	a = d*sy/2;
993e12c5d1SDavid du Colombier 	*u = d*(*u) + f1*h;
1003e12c5d1SDavid du Colombier 	*v = (-1-log(e1*e1+e2*e2))*a + f2*h*sy + a;
1013e12c5d1SDavid du Colombier 	return(1);
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier 
1043e12c5d1SDavid du Colombier void
cdiv2(double c1,double c2,double d1,double d2,double * e1,double * e2)1053e12c5d1SDavid du Colombier cdiv2(double c1, double c2, double d1, double d2, double *e1, double *e2)
1063e12c5d1SDavid du Colombier {
1073e12c5d1SDavid du Colombier 	double t;
1083e12c5d1SDavid du Colombier 	if(fabs(d2)>fabs(d1)) {
1093e12c5d1SDavid du Colombier 		t = d1, d1 = d2, d2 = t;
1103e12c5d1SDavid du Colombier 		t = c1, c1 = c2, c2 = t;
1113e12c5d1SDavid du Colombier 	}
1123e12c5d1SDavid du Colombier 	if(fabs(d1)>ROOTINF)
1133e12c5d1SDavid du Colombier 		*e2 = ROOTINF*ROOTINF;
1143e12c5d1SDavid du Colombier 	else
1153e12c5d1SDavid du Colombier 		*e2 = d1*d1 + d2*d2;
1163e12c5d1SDavid du Colombier 	t = d2/d1;
1173e12c5d1SDavid du Colombier 	*e1 = (c1+t*c2)/(d1+t*d2); /* (c1*d1+c2*d2)/(d1*d1+d2*d2) */
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier /* complex square root of |x|+iy */
1213e12c5d1SDavid du Colombier void
csqr(double c1,double c2,double * e1,double * e2)1223e12c5d1SDavid du Colombier csqr(double c1, double c2, double *e1, double *e2)
1233e12c5d1SDavid du Colombier {
1243e12c5d1SDavid du Colombier 	double r2;
1253e12c5d1SDavid du Colombier 	r2 = c1*c1 + c2*c2;
1263e12c5d1SDavid du Colombier 	if(r2<=0) {
1273e12c5d1SDavid du Colombier 		*e1 = *e2 = 0;
1283e12c5d1SDavid du Colombier 		return;
1293e12c5d1SDavid du Colombier 	}
1303e12c5d1SDavid du Colombier 	*e1 = sqrt((sqrt(r2) + fabs(c1))/2);
1313e12c5d1SDavid du Colombier 	*e2 = c2/(*e1*2);
1323e12c5d1SDavid du Colombier }
133