/// <summary> /// The Faddeeva function or Kramp function is a scaled complex complementary error function. /// </summary> /// <param name="z">The argument z.</param> /// <returns>The evaluated value.</returns> public static ScalarValue Faddeeva(ScalarValue z) { if (z.Im < 0.0) { return(2.0 * (-z * z).Exp() - Faddeeva(-z)); } if (z.Re < 0.0) { return(Faddeeva(-z.Conjugate()).Conjugate()); } var r = z.Abs(); if (r < 2.0) { return((-z * z).Exp() * (1.0 - Erf_Series(-ScalarValue.I * z))); } else if ((z.Im < 0.1) && (z.Re < 30.0)) { return(Taylor(new ScalarValue(z.Re), Math.Exp(-z.Re * z.Re) + 2.0 * Dawson.DawsonIntegral(z.Re) / Helpers.SqrtPI * ScalarValue.I, new ScalarValue(0.0, z.Im))); } else if (r > 7.0) { return(ContinuedFraction(z)); } return(Weideman(z)); }
static ScalarValue LambertW(ScalarValue x) { var EI = 1.0 / Math.E; // use an initial approximation var W = ScalarValue.Zero; var abs = x.Abs(); if (abs < EI / 2.0) { W = SeriesSmall(x); if ((x + EI).Abs() < 1e-6) { return(W); } } else if (abs < EI) { W = SeriesZero(x); } else if (abs > Math.E) { W = SeriesLarge(x); } else { W = new ScalarValue(0.5); } return(Halley(x, W)); }
/// <summary> /// Computes the complex Riemann Zeta function. /// </summary> /// <param name="s">The complex argument.</param> /// <returns>The (in general complex) value.</returns> public static ScalarValue RiemannZeta(ScalarValue s) { if (s == 1.0) { return(new ScalarValue(Double.PositiveInfinity)); } else if (s.Re >= 0.0) { return(RiemannZetaGt0(s)); } //See real zeta function for more information var zeta_one_minus_s = RiemannZeta1msLt0(s); var sin_term = (0.5 * Math.PI * s).Sin() / Math.PI; var sabs = s.Abs(); if (sin_term == 0.0) { return(ScalarValue.Zero); } else if (sabs < 170) { //See below int n = (int)Math.Floor(sabs / 10.0); var p = new ScalarValue(2.0 * Math.PI).Pow(s + 10.0 * n) / Helpers.TwoPIpow[n]; var g = Gamma.LinearGamma(1.0 - s); return(p * g * sin_term * zeta_one_minus_s); } throw new YAMPNumericOverflowException("Zeta"); }
public static ScalarValue Gegenbauer(Int32 n, Double alpha, ScalarValue x) { if (n < 0) throw new YAMPArgumentRangeException("n"); if (alpha <= 0) throw new YAMPArgumentRangeException("alpha", 0); if (x.Abs() > 1.0) throw new YAMPArgumentRangeException("x", -1, 1); var C0 = ScalarValue.One; if (n == 0) { return C0; } var C1 = 2.0 * alpha * x; if (n == 1) { return C1; } for (var k = 2; k <= n; k++) { var Ck = (2 * x * (k + alpha - 1) * C1 - (k + 2 * alpha - 2) * C0) / k; C0 = C1; C1 = Ck; } return C1; }
static ScalarValue LambertW(ScalarValue x) { var EI = 1.0 / Math.E; // use an initial approximation var W = ScalarValue.Zero; var abs = x.Abs(); if (abs < EI / 2.0) { W = SeriesSmall(x); if ((x + EI).Abs() < 1e-6) { return W; } } else if (abs < EI) { W = SeriesZero(x); } else if (abs > Math.E) { W = SeriesLarge(x); } else { W = new ScalarValue(0.5); } return Halley(x, W); }
/// <summary> /// Computes the complex error function erf(z). /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The value of erf(z).</returns> public static ScalarValue Erf(ScalarValue z) { if (z.Abs() < 4.0) { return(Erf_Series(z)); } else if (z.Re < 0.0) { return((-z * z).Exp() * Faddeeva(-ScalarValue.I * z) - 1.0); } return(1.0 - (-z * z).Exp() * Faddeeva(ScalarValue.I * z)); }
/// <summary> /// Computes the complex (log) gamma function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The evaluated value.</returns> public static ScalarValue LogGamma(ScalarValue z) { if (z.Re < 0.0) { return(new ScalarValue(double.PositiveInfinity)); } if (z.Abs() > 15.0) { return(LogGamma_Stirling(z)); } return(LanczosLogGamma(z)); }
public static ScalarValue Gegenbauer(Int32 n, Double alpha, ScalarValue x) { if (n < 0) { throw new YAMPArgumentRangeException("n"); } if (alpha <= 0) { throw new YAMPArgumentRangeException("alpha", 0); } if (x.Abs() > 1.0) { throw new YAMPArgumentRangeException("x", -1, 1); } var C0 = ScalarValue.One; if (n == 0) { return(C0); } var C1 = 2.0 * alpha * x; if (n == 1) { return(C1); } for (var k = 2; k <= n; k++) { var Ck = (2 * x * (k + alpha - 1) * C1 - (k + 2 * alpha - 2) * C0) / k; C0 = C1; C1 = Ck; } return(C1); }
/// <summary> /// Computes the complex dilogarithm function, also called Spence's function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The value Li<sub>2</sub>(z).</returns> public static ScalarValue DiLog(ScalarValue z) { ScalarValue f; double a0 = z.Abs(); if (a0 > 1.0) { // outside the unit disk, reflect into the unit disk var ln = (-z).Ln(); f = -Math.PI * Math.PI / 6.0 - ln * ln / 2.0 - DiLog(1.0 / z); } else { // inside the unit disk... if (a0 < 0.75) { f = DiLog0(z); } else if (z.Re < 0.0) { f = DiLog(z * z) / 2.0 - DiLog(-z); } else { var e = 1.0 - z; f = e.Abs() < 0.5 ? DiLog1(e) : DiLog_Log_Series(z); } } if ((z.Re > 1.0) && (Math.Sign(f.Im) != Math.Sign(z.Im))) { f = f.Conjugate(); } return(f); }
/// <summary> /// Computes the complex dilogarithm function, also called Spence's function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The value Li<sub>2</sub>(z).</returns> public static ScalarValue DiLog(ScalarValue z) { var f = default(ScalarValue); var a0 = z.Abs(); if (a0 > 1.0) { // outside the unit disk, reflect into the unit disk var ln = (-z).Ln(); f = -Math.PI * Math.PI / 6.0 - ln * ln / 2.0 - DiLog(1.0 / z); } else { // inside the unit disk... if (a0 < 0.75) { f = DiLog0(z); } else if (z.Re < 0.0) { f = DiLog(z * z) / 2.0 - DiLog(-z); } else { var e = 1.0 - z; f = e.Abs() < 0.5 ? DiLog1(e) : DiLog_Log_Series(z); } } if ((z.Re > 1.0) && (Math.Sign(f.Im) != Math.Sign(z.Im))) { f = f.Conjugate(); } return f; }
/// <summary> /// Computes the complex Riemann Zeta function. /// </summary> /// <param name="s">The complex argument.</param> /// <returns>The (in general complex) value.</returns> public static ScalarValue RiemannZeta(ScalarValue s) { if (s == 1.0) { return new ScalarValue(Double.PositiveInfinity); } else if (s.Re >= 0.0) { return RiemannZetaGt0(s); } //See real zeta function for more information var zeta_one_minus_s = RiemannZeta1msLt0(s); var sin_term = (0.5 * Math.PI * s).Sin() / Math.PI; var sabs = s.Abs(); if (sin_term == 0.0) { return ScalarValue.Zero; } else if (sabs < 170) { //See below int n = (int)Math.Floor(sabs / 10.0); var p = new ScalarValue(2.0 * Math.PI).Pow(s + 10.0 * n) / Helpers.TwoPIpow[n]; var g = Gamma.LinearGamma(1.0 - s); return p * g * sin_term * zeta_one_minus_s; } throw new YAMPNumericOverflowException("Zeta"); }
public static ScalarValue HurwitzZeta(ScalarValue s, ScalarValue q) { if (s.Re <= 1.0) { throw new YAMPArgumentRangeException("s", 1.0); } if (q.Re <= 0.0) { throw new YAMPArgumentRangeException("q", 0.0); } var max_bits = 54.0; var ln_term0 = -s *q.Log(); var qabs = q.Abs(); var sabs = s.Abs(); var ss = s; if ((sabs > max_bits && qabs < 1.0) || (sabs > 0.5 * max_bits && qabs < 0.25)) { return(q.Pow(-ss)); } else if (sabs > 0.5 * max_bits && qabs < 1.0) { var p1 = q.Pow(-ss); var p2 = (q / (1.0 + q)).Pow(ss); var p3 = (q / (2.0 + q)).Pow(ss); return(p1 * (1.0 + p2 + p3)); } /* Euler-Maclaurin summation formula * [Moshier, p. 400, with several typo corrections] */ const int jmax = 12; const int kmax = 10; var pmax = (kmax + q).Pow(-ss); var scp = s; var pcp = pmax / (kmax + q); var ans = pmax * ((kmax + q) / (s - 1.0) + 0.5); for (var k = 0; k < kmax; k++) { ans += (k + q).Pow(-ss); } for (var j = 0; j <= jmax; j++) { var delta = COEFFICIENTS[j + 1] * scp * pcp; ans += delta; if ((delta / ans).Abs() < 0.5 * Double.Epsilon) { break; } scp *= (s + 2 * j + 1) * (s + 2 * j + 2); pcp /= (kmax + q) * (kmax + q); } return(ans); }
/// <summary> /// The Faddeeva function or Kramp function is a scaled complex complementary error function. /// </summary> /// <param name="z">The argument z.</param> /// <returns>The evaluated value.</returns> public static ScalarValue Faddeeva(ScalarValue z) { if (z.Im < 0.0) return 2.0 * (-z * z).Exp() - Faddeeva(-z); if (z.Re < 0.0) return Faddeeva(-z.Conjugate()).Conjugate(); var r = z.Abs(); if (r < 2.0) return (-z * z).Exp() * (1.0 - Erf_Series(-ScalarValue.I * z)); else if ((z.Im < 0.1) && (z.Re < 30.0)) return Taylor(new ScalarValue(z.Re), Math.Exp(-z.Re * z.Re) + 2.0 * Dawson.DawsonIntegral(z.Re) / Helpers.SqrtPI * ScalarValue.I, new ScalarValue(0.0, z.Im)); else if (r > 7.0) return ContinuedFraction(z); return Weideman(z); }
static ScalarValue Zernike(int n, int m, ScalarValue rho) { if (n < 0) { throw new YAMPArgumentRangeException("n"); } if ((m < 0) || (m > n)) { throw new YAMPArgumentRangeException("m", "n >= m >= 0"); } // n and m have the same parity if ((n - m) % 2 != 0) { return(ScalarValue.Zero); } // R00 if (n == 0) { return(ScalarValue.One); } var absrho = rho.Abs(); if ((absrho < 0.0) || (absrho > 1.0)) { throw new YAMPNotConvergedException("zernike"); } // R^{m}_m var r2 = rho.Pow(new ScalarValue(m)); if (n == m) { return(r2); } // R^{m+1}_{m+1} var k = m; var r1 = r2 * rho; while (true) { k += 2; // * // \ // * recurrence involving two lesser m's // / // * // 2n R^{m+1}_{n-1} = (n+m) R^{m}_{n-2} + (n-m) R^{m}_{n} var r0 = ((2 * k) * rho * r1 - (k + m) * r2) / (k - m); if (k == n) { return(r0); } // * // / // * recurrence involving two greater m's // \ // * // var rp = (2 * (k + 1) * rho * r0 - (k - m) * r1) / (k + m + 2); r2 = r0; r1 = rp; } }
/// <summary> /// Computes the complex (log) gamma function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The evaluated value.</returns> public static ScalarValue LogGamma(ScalarValue z) { if (z.Re < 0.0) return new ScalarValue(double.PositiveInfinity); if (z.Abs() > 15.0) return LogGamma_Stirling(z); return LanczosLogGamma(z); }
static ScalarValue Zernike(int n, int m, ScalarValue rho) { if (n < 0) throw new YAMPArgumentRangeException("n"); if ((m < 0) || (m > n)) throw new YAMPArgumentRangeException("m", "n >= m >= 0"); // n and m have the same parity if ((n - m) % 2 != 0) { return ScalarValue.Zero; } // R00 if (n == 0) { return ScalarValue.One; } var absrho = rho.Abs(); if ((absrho < 0.0) || (absrho > 1.0)) throw new YAMPNotConvergedException("zernike"); // R^{m}_m var r2 = rho.Pow(new ScalarValue(m)); if (n == m) { return r2; } // R^{m+1}_{m+1} var k = m; var r1 = r2 * rho; while (true) { k += 2; // * // \ // * recurrence involving two lesser m's // / // * // 2n R^{m+1}_{n-1} = (n+m) R^{m}_{n-2} + (n-m) R^{m}_{n} var r0 = ((2 * k) * rho * r1 - (k + m) * r2) / (k - m); if (k == n) { return r0; } // * // / // * recurrence involving two greater m's // \ // * // var rp = (2 * (k + 1) * rho * r0 - (k - m) * r1) / (k + m + 2); r2 = r0; r1 = rp; } }
public static ScalarValue HurwitzZeta(ScalarValue s, ScalarValue q) { if (s.Re <= 1.0) throw new YAMPArgumentRangeException("s", 1.0); if (q.Re <= 0.0) throw new YAMPArgumentRangeException("q", 0.0); var max_bits = 54.0; var ln_term0 = -s * q.Log(); var qabs = q.Abs(); var sabs = s.Abs(); var ss = s; if ((sabs > max_bits && qabs < 1.0) || (sabs > 0.5 * max_bits && qabs < 0.25)) { return q.Pow(-ss); } else if (sabs > 0.5 * max_bits && qabs < 1.0) { var p1 = q.Pow(-ss); var p2 = (q / (1.0 + q)).Pow(ss); var p3 = (q / (2.0 + q)).Pow(ss); return p1 * (1.0 + p2 + p3); } /* Euler-Maclaurin summation formula * [Moshier, p. 400, with several typo corrections] */ const int jmax = 12; const int kmax = 10; var pmax = (kmax + q).Pow(-ss); var scp = s; var pcp = pmax / (kmax + q); var ans = pmax * ((kmax + q) / (s - 1.0) + 0.5); for (var k = 0; k < kmax; k++) { ans += (k + q).Pow(-ss); } for (var j = 0; j <= jmax; j++) { var delta = COEFFICIENTS[j + 1] * scp * pcp; ans += delta; if ((delta / ans).Abs() < 0.5 * Double.Epsilon) { break; } scp *= (s + 2 * j + 1) * (s + 2 * j + 2); pcp /= (kmax + q) * (kmax + q); } return ans; }
/// <summary> /// Computes the complex error function erf(z). /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The value of erf(z).</returns> public static ScalarValue Erf(ScalarValue z) { if (z.Abs() < 4.0) return Erf_Series(z); else if (z.Re < 0.0) return (-z * z).Exp() * Faddeeva(-ScalarValue.I * z) - 1.0; return 1.0 - (-z * z).Exp() * Faddeeva(ScalarValue.I * z); }