/// <summary> /// Returns K{n}(x) for integer order /// </summary> /// <param name="n"></param> /// <param name="x"></param> /// <returns></returns> public static double KN(int n, double x) { if (x < 0) { Policies.ReportDomainError("BesselK(v: {0}, x: {1}): Requires x >= 0 for real result", n, x); return(double.NaN); } if (x == 0) { return(double.PositiveInfinity); } // even function // K{-n}(z) = K{n}(z) if (n < 0) { n = -n; } if (n == 0) { return(K0(x)); } if (n == 1) { return(K1(x)); } double v = n; // Hankel is fast, and reasonably accurate, saving us from many recurrences. if (x >= HankelAsym.IKMinX(v)) { return(HankelAsym.K(v, x)); } // the uniform expansion is here as a last resort // to limit the number of recurrences, but it is less accurate. if (UniformAsym.IsIKAvailable(v, x)) { return(UniformAsym.K(v, x)); } // Since K{v}(x) has a (e^-x)/sqrt(x) multiplier // using recurrence can underflow too quickly for large x, // so, use a scaled version double result; if (x > 1) { double prev = K0(x, true); double current = K1(x, true); // for large v and x this number can get very large // maximum observed K(1000,10) = 2^6211 var(Kv, _, binaryScale) = Recurrence.ForwardK_B(1, x, n - 1, current, prev); // Compute: value * 2^(binaryScale) * e^-x if (x < -DoubleX.MinLogValue) { DoubleX exs = DoubleX.Ldexp(DoubleX.Exp(-x), binaryScale); result = Math2.Ldexp(Kv * exs.Mantissa, exs.Exponent); } else { result = Math.Exp(-x + Math.Log(Kv) + binaryScale * Constants.Ln2); } } else { double prev = K0(x); double current = K1(x); result = Recurrence.ForwardK(1, x, n - 1, current, prev).Kvpn; } return(result); }