可爱的科尔鸭
using System;
namespace Legalsoft.Truffer
{
/// <summary>
/// Elliptic Integrals and Jacobian Elliptic Functions
/// </summary>
public class Elliptic
{
public Elliptic()
{
}
private static double rc(double x, double y)
{
const double ERRTOL = 0.0012;
const double THIRD = 1.0 / 3.0;
const double C1 = 0.3;
const double C2 = 1.0 / 7.0;
const double C3 = 0.375;
const double C4 = 9.0 / 22.0;
const double TINY = 5.0 * float.MinValue;
const double BIG = 0.2 * double.MaxValue;
double COMP1 = 2.236 / Math.Sqrt(TINY);
double COMP2 = Globals.SQR(TINY * BIG) / 25.0;
//if (x < 0.0 || y == 0.0 || (x + Math.Abs(y)) < TINY || (x + Math.Abs(y)) > BIG || (y < -COMP1 && x > 0.0 && x < COMP2))
if (x < 0.0 || Math.Abs(y) <= float.Epsilon || (x + Math.Abs(y)) < TINY || (x + Math.Abs(y)) > BIG || (y < -COMP1 && x > 0.0 && x < COMP2))
{
throw new Exception("invalid arguments in rc");
}
double xt;
double yt;
double w;
if (y > 0.0)
{
xt = x;
yt = y;
w = 1.0;
}
else
{
xt = x - y;
yt = -y;
w = Math.Sqrt(x) / Math.Sqrt(xt);
}
double s;
double ave;
do
{
double alamb = 2.0 * Math.Sqrt(xt) * Math.Sqrt(yt) + yt;
xt = 0.25 * (xt + alamb);
yt = 0.25 * (yt + alamb);
ave = THIRD * (xt + yt + yt);
s = (yt - ave) / ave;
} while (Math.Abs(s) > ERRTOL);
return w * (1.0 + s * s * (C1 + s * (C2 + s * (C3 + s * C4)))) / Math.Sqrt(ave);
}
private static double rd(double x, double y, double z)
{
const double ERRTOL = 0.0015;
const double C1 = 3.0 / 14.0;
const double C2 = 1.0 / 6.0;
const double C3 = 9.0 / 22.0;
const double C4 = 3.0 / 26.0;
const double C5 = 0.25 * C3;
const double C6 = 1.5 * C4;
double TINY = 2.0 * Math.Pow(double.MaxValue, -2.0 / 3.0);
double BIG = 0.1 * ERRTOL * Math.Pow(float.MinValue, -2.0 / 3.0);
double ave;
double delx;
double dely;
double delz;
if (Math.Min(x, y) < 0.0 || Math.Min(x + y, z) < TINY || Math.Max(Math.Max(x, y), z) > BIG)
{
throw new Exception("invalid arguments in rd");
}
double xt = x;
double yt = y;
double zt = z;
double sum = 0.0;
double fac = 1.0;
do
{
double sqrtx = Math.Sqrt(xt);
double sqrty = Math.Sqrt(yt);
double sqrtz = Math.Sqrt(zt);
double alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz;
sum += fac / (sqrtz * (zt + alamb));
fac = 0.25 * fac;
xt = 0.25 * (xt + alamb);
yt = 0.25 * (yt + alamb);
zt = 0.25 * (zt + alamb);
ave = 0.2 * (xt + yt + 3.0 * zt);
delx = (ave - xt) / ave;
dely = (ave - yt) / ave;
delz = (ave - zt) / ave;
} while (Math.Max(Math.Max(Math.Abs(delx), Math.Abs(dely)), Math.Abs(delz)) > ERRTOL);
double ea = delx * dely;
double eb = delz * delz;
double ec = ea - eb;
double ed = ea - 6.0 * eb;
double ee = ed + ec + ec;
return 3.0 * sum + fac * (1.0 + ed * (-C1 + C5 * ed - C6 * delz * ee) + delz * (C2 * ee + delz * (-C3 * ec + delz * C4 * ea))) / (ave * Math.Sqrt(ave));
}
private static double rf(double x, double y, double z)
{
const double ERRTOL = 0.0025;
const double THIRD = 1.0 / 3.0;
const double C1 = 1.0 / 24.0;
const double C2 = 0.1;
const double C3 = 3.0 / 44.0;
const double C4 = 1.0 / 14.0;
double TINY = 5.0 * float.MinValue;
double BIG = 0.2 * double.MaxValue;
double ave;
double delx;
double dely;
double delz;
if (Math.Min(Math.Min(x, y), z) < 0.0 || Math.Min(Math.Min(x + y, x + z), y + z) < TINY || Math.Max(Math.Max(x, y), z) > BIG)
{
throw new Exception("invalid arguments in rf");
}
double xt = x;
double yt = y;
double zt = z;
do
{
double sqrtx = Math.Sqrt(xt);
double sqrty = Math.Sqrt(yt);
double sqrtz = Math.Sqrt(zt);
double alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz;
xt = 0.25 * (xt + alamb);
yt = 0.25 * (yt + alamb);
zt = 0.25 * (zt + alamb);
ave = THIRD * (xt + yt + zt);
delx = (ave - xt) / ave;
dely = (ave - yt) / ave;
delz = (ave - zt) / ave;
} while (Math.Max(Math.Max(Math.Abs(delx), Math.Abs(dely)), Math.Abs(delz)) > ERRTOL);
double e2 = delx * dely - delz * delz;
double e3 = delx * dely * delz;
return (1.0 + (C1 * e2 - C2 - C3 * e3) * e2 + C4 * e3) / Math.Sqrt(ave);
}
private static double rj(double x, double y, double z, double p)
{
const double ERRTOL = 0.0015;
const double C1 = 3.0 / 14.0;
const double C2 = 1.0 / 3.0;
const double C3 = 3.0 / 22.0;
const double C4 = 3.0 / 26.0;
double C5 = 0.75 * C3;
double C6 = 1.5 * C4;
double C7 = 0.5 * C2;
double C8 = C3 + C3;
double TINY = Math.Pow(5.0 * float.MinValue, 1.0 / 3.0);
double BIG = 0.3 * Math.Pow(0.2 * double.MaxValue, 1.0 / 3.0);
double a = 0.0;
double ave;
double b = 0.0;
double delp;
double delx;
double dely;
double delz;
double rcx = 0.0;
if (Math.Min(Math.Min(x, y), z) < 0.0 || Math.Min(Math.Min(x + y, x + z), Math.Min(y + z, Math.Abs(p))) < TINY || Math.Max(Math.Max(x, y), Math.Max(z, Math.Abs(p))) > BIG)
{
throw new Exception("invalid arguments in rj");
}
double sum = 0.0;
double fac = 1.0;
double xt;
double yt;
double zt;
double pt;
if (p > 0.0)
{
xt = x;
yt = y;
zt = z;
pt = p;
}
else
{
xt = Math.Min(Math.Min(x, y), z);
zt = Math.Max(Math.Max(x, y), z);
yt = x + y + z - xt - zt;
a = 1.0 / (yt - p);
b = a * (zt - yt) * (yt - xt);
pt = yt + b;
double rho = xt * zt / yt;
double tau = p * pt / yt;
rcx = rc(rho, tau);
}
do
{
double sqrtx = Math.Sqrt(xt);
double sqrty = Math.Sqrt(yt);
double sqrtz = Math.Sqrt(zt);
double alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz;
double alpha = Globals.SQR(pt * (sqrtx + sqrty + sqrtz) + sqrtx * sqrty * sqrtz);
double beta = pt * Globals.SQR(pt + alamb);
sum += fac * rc(alpha, beta);
fac = 0.25 * fac;
xt = 0.25 * (xt + alamb);
yt = 0.25 * (yt + alamb);
zt = 0.25 * (zt + alamb);
pt = 0.25 * (pt + alamb);
ave = 0.2 * (xt + yt + zt + pt + pt);
delx = (ave - xt) / ave;
dely = (ave - yt) / ave;
delz = (ave - zt) / ave;
delp = (ave - pt) / ave;
} while (Math.Max(Math.Max(Math.Abs(delx), Math.Abs(dely)), Math.Max(Math.Abs(delz), Math.Abs(delp))) > ERRTOL);
double ea = delx * (dely + delz) + dely * delz;
double eb = delx * dely * delz;
double ec = delp * delp;
double ed = ea - 3.0 * ec;
double ee = eb + 2.0 * delp * (ea - ec);
double ans = 3.0 * sum + fac * (1.0 + ed * (-C1 + C5 * ed - C6 * ee) + eb * (C7 + delp * (-C8 + delp * C4)) + delp * ea * (C2 - delp * C3) - C2 * delp * ec) / (ave * Math.Sqrt(ave));
if (p <= 0.0)
{
ans = a * (b * ans + 3.0 * (rcx - rf(xt, yt, zt)));
}
return ans;
}
private static double ellf(double phi, double ak)
{
double s = Math.Sin(phi);
return s * rf(Globals.SQR(Math.Cos(phi)), (1.0 - s * ak) * (1.0 + s * ak), 1.0);
}
private static double elle(double phi, double ak)
{
double s = Math.Sin(phi);
double cc = Globals.SQR(Math.Cos(phi));
double q = (1.0 - s * ak) * (1.0 + s * ak);
return s * (rf(cc, q, 1.0) - (Globals.SQR(s * ak)) * rd(cc, q, 1.0) / 3.0);
}
private static double ellpi(double phi, double en, double ak)
{
double s = Math.Sin(phi);
double enss = en * s * s;
double cc = Globals.SQR(Math.Cos(phi));
double q = (1.0 - s * ak) * (1.0 + s * ak);
return s * (rf(cc, q, 1.0) - enss * rj(cc, q, 1.0, 1.0 + enss) / 3.0);
}
private static void sncndn(double uu, double emmc, ref double sn, ref double cn, ref double dn)
{
const double CA = 1.0e-8;
int l = 0;
double c = 0.0;
double d = 0.0;
double[] em = new double[13];
double[] en = new double[13];
double emc = emmc;
double u = uu;
if (emc != 0.0)
{
bool bo = (emc < 0.0);
if (bo)
{
d = 1.0 - emc;
emc /= -1.0 / d;
u *= (d = Math.Sqrt(d));
}
double a = 1.0;
dn = 1.0;
for (int i = 0; i < 13; i++)
{
l = i;
em[i] = a;
en[i] = (emc = Math.Sqrt(emc));
c = 0.5 * (a + emc);
if (Math.Abs(a - emc) <= CA * a)
{
break;
}
emc *= a;
a = c;
}
u *= c;
sn = Math.Sin(u);
cn = Math.Cos(u);
if (sn != 0.0)
{
a = cn / sn;
c *= a;
for (int ii = l; ii >= 0; ii--)
{
double b = em[ii];
a *= c;
c *= dn;
dn = (en[ii] + a) / (b + a);
a = c / b;
}
a = 1.0 / Math.Sqrt(c * c + 1.0);
sn = (sn >= 0.0 ? a : -a);
cn = c * sn;
}
if (bo)
{
a = dn;
dn = cn;
cn = a;
sn /= d;
}
}
else
{
cn = 1.0 / Math.Cosh(u);
dn = cn;
sn = Math.Tanh(u);
}
}
}
}