How can I implement the Gaussian Hypergeometric Function 2F1(a, b, c, z) in C#, with the ability on handling negative and large z values?
2F1 is part of the integral of a certain equation resulting in the following implementation:
internal static double HCWR(double distance, double n)
{
double geometricResult = 2F1(1, 1 / n, 1 + 1 / n, -Math.Pow(distance, -n));
return (Math.Pow(distance, -n) * geometricResult);
}
n can be any number bigger or equal to 2 and distance can be any number in the interval (0,1].
Values like a = 1, b = 0.5, c = 1.5 and z = -25.0, which should be 0.27468, aren't handled well in every implementation. CenterSpace refuses every |z| > 1 and MathNet.Numerics returns -infinity, while I prefer an implementation that can handle non-integer values for z.
Credit to Alander for the comment.
Since in my example the domain n≥2 and distance∈(0,1] is applied, it follows that for
z=-(distance^(-n)) we have z≤−1.
Thus, 0<z/(z−1)<1 holds. We can apply the transformation
2F1(a,b,c,z) = (1-z)^(-a) * 2F1(a, c-b, c, z/(z-1))
and implement the function in this domain as follows:
internal static double HCWR(double distance, double n)
{
double z = -Math.Pow(distance, -n);
double c = 1 + 1 / n;
double b = 1 / n;
double a = 1;
double factorTransformed = Math.Pow(1 - z, -a);
double bTransformed = c - b;
double zTransformed = z / (z - 1);
double geometricResult = factorTransformed * CenterSpace.NMath.Core.SpecialFunctions.Hypergeometric2F1(a, bTransformed, c, zTransformed);
return (Math.Pow(distance, -n) * geometricResult);
}
resulting in the following final implementation:
internal static double HCWR(double distance, double n)
{
int a = 1;
int b = 1;
double c = 1 + 1 / n;
double z = 1 / (1 + Math.Pow(distance, n));
return z * CenterSpace.NMath.Core.SpecialFunctions.Hypergeometric2F1(a, b, c, z);
}