public static void CheckUnderFlow(SpecialFunctionResult r) { if (System.Math.Abs(r.Val) < PZMath_machine.PZMath_DBL_MIN) { string error = "underflow" + PZMath_errno.PZMath_EUNDRFLW; throw new ApplicationException(error); } }
public static int MultiplyE(double x, double y, ref SpecialFunctionResult result) { double ax = System.Math.Abs(x); double ay = System.Math.Abs(y); if (x == 0.0 || y == 0.0) { /* It is necessary to eliminate this immediately. */ result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if ((ax <= 1.0 && ay >= 1.0) || (ay <= 1.0 && ax >= 1.0)) { /* Straddling 1.0 is always safe. */ result.Val = x * y; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { double f = 1.0 - 2.0 * PZMath_machine.PZMath_DBL_EPSILON; double min = System.Math.Min(System.Math.Abs(x), System.Math.Abs(y)); double max = System.Math.Max(System.Math.Abs(x), System.Math.Abs(y)); if (max < 0.9 * PZMath_machine.PZMath_SQRT_DBL_MAX || min < (f * PZMath_machine.PZMath_DBL_MAX) / max) { result.Val = x * y; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); PZMath_errno.CheckUnderFlow(result); return PZMath_errno.PZMath_SUCCESS; } else { PZMath_errno.OverFlowError(ref result); } } return PZMath_errno.PZMath_SUCCESS; }
/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/ public static int LnGammaE(double x, ref SpecialFunctionResult result) { if (System.Math.Abs(x - 1.0) < 0.01) { /* Note that we must amplify the errors * from the Pade evaluations because of * the way we must pass the argument, i.e. * writing (1-x) is a loss of precision * when x is near 1. */ int stat = LnGamma1Pade(x - 1.0, ref result); result.Err *= 1.0 / (PZMath_machine.PZMath_DBL_EPSILON + System.Math.Abs(x - 1.0)); return stat; } else if (System.Math.Abs(x - 2.0) < 0.01) { int stat = LnGamma2Pade(x - 2.0, ref result); result.Err *= 1.0 / (PZMath_machine.PZMath_DBL_EPSILON + System.Math.Abs(x - 2.0)); return stat; } else if (x >= 0.5) { return LnGammaLanczos(x, ref result); } else if (x == 0.0) { PZMath_errno.DomainError(ref result); } else if (System.Math.Abs(x) < 0.02) { double sgn = 0.0; return LnGammaSgn0(x, ref result, ref sgn); } else if (x > -0.5 / (PZMath_machine.PZMath_DBL_EPSILON * PZMath.M_PI)) { /* Try to extract a fractional * part from x. */ double z = 1.0 - x; double s = System.Math.Sin(PZMath.M_PI * z); double abss = System.Math.Abs(s); if (s == 0.0) { PZMath_errno.DomainError(ref result); } else if (abss < PZMath.M_PI * 0.015) { /* x is near a negative integer, -N */ if (x < int.MinValue + 2.0) { result.Val = 0.0; result.Err = 0.0; PZMath_errno.ERROR("error", PZMath_errno.PZMath_EROUND); } else { int N = -(int)(x - 0.5); double eps = x + N; double sgn = 0.0; return LnGammaSgnSing(N, eps, ref result, ref sgn); } } else { SpecialFunctionResult lg_z = new SpecialFunctionResult(); LnGammaLanczos(z, ref lg_z); result.Val = PZMath.M_LNPI - (System.Math.Log(abss) + lg_z.Val); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val) + lg_z.Err; return PZMath_errno.PZMath_SUCCESS; } } else { /* |x| was too large to extract any fractional part */ result.Val = 0.0; result.Err = 0.0; PZMath_errno.ERROR("error", PZMath_errno.PZMath_EROUND); } return PZMath_errno.PZMath_SUCCESS; }
public static int HZetaE(double s, double q, ref SpecialFunctionResult result) { if (s <= 1.0 || q <= 0.0) { PZMath_errno.DomainError(ref result); } else { double max_bits = 54.0; double ln_term0 = -s * System.Math.Log(q); if (ln_term0 < PZMath_machine.PZMath_LOG_DBL_MIN + 1.0) { PZMath_errno.UnderFlowError(ref result); } else if (ln_term0 > PZMath_machine.PZMath_LOG_DBL_MAX - 1.0) { PZMath_errno.OverFlowError(ref result); } else if ((s > max_bits && q < 1.0) || (s > 0.5 * max_bits && q < 0.25)) { result.Val = System.Math.Pow(q, -s); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else if (s > 0.5 * max_bits && q < 1.0) { double p1 = System.Math.Pow(q, -s); double p2 = System.Math.Pow(q / (1.0 + q), s); double p3 = System.Math.Pow(q / (2.0 + q), s); result.Val = p1 * (1.0 + p2 + p3); result.Err = PZMath_machine.PZMath_DBL_EPSILON * (0.5 * s + 2.0) * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { /* Euler-Maclaurin summation formula * [Moshier, p. 400, with several typo corrections] */ int jmax = 12; int kmax = 10; int j, k; double pmax = System.Math.Pow(kmax + q, -s); double scp = s; double pcp = pmax / (kmax + q); double ans = pmax * ((kmax + q) / (s - 1.0) + 0.5); for (k = 0; k < kmax; k++) { ans += System.Math.Pow(k + q, -s); } for (j = 0; j <= jmax; j++) { double delta = hzeta_c[j + 1] * scp * pcp; ans += delta; if (System.Math.Abs(delta / ans) < 0.5 * PZMath_machine.PZMath_DBL_EPSILON) break; scp *= (s + 2 * j + 1) * (s + 2 * j + 2); pcp /= (kmax + q) * (kmax + q); } result.Val = ans; result.Err = 2.0 * (jmax + 1.0) * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(ans); return PZMath_errno.PZMath_SUCCESS; } } return PZMath_errno.PZMath_SUCCESS; }
public static int LnGamma2Pade(double eps, ref SpecialFunctionResult result) { /* Use (2,2) Pade for Log[Gamma[2+eps]]/eps * plus a correction series. */ double n1 = 1.000895834786669227164446568; double n2 = 4.209376735287755081642901277; double d1 = 2.618851904903217274682578255; double d2 = 10.85766559900983515322922936; double num = (eps + n1) * (eps + n2); double den = (eps + d1) * (eps + d2); double pade = 2.85337998765781918463568869 * num / den; double c0 = 0.0001139406357036744; double c1 = -0.0001365435269792533; double c2 = 0.0001067287169183665; double c3 = -0.0000693271800931282; double c4 = 0.0000407220927867950; double eps5 = eps * eps * eps * eps * eps; double corr = eps5 * (c0 + eps * (c1 + eps * (c2 + eps * (c3 + c4 * eps)))); result.Val = eps * (pade + corr); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; }
public static int GammaInvE(double x, ref SpecialFunctionResult result) { if (x <= 0.0 && x == System.Math.Floor(x)) { /* negative integer */ result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (x < 0.5) { SpecialFunctionResult lng = new SpecialFunctionResult(); double sgn = 0.0; int stat_lng = LnGammaSgnE(x, ref lng, ref sgn); if (stat_lng == PZMath_errno.PZMath_EDOM) { result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (stat_lng != PZMath_errno.PZMath_SUCCESS) { result.Val = 0.0; result.Err = 0.0; return stat_lng; } else { return Exp.ExpMultErrE(-lng.Val, lng.Err, sgn, 0.0, ref result); } } else { SpecialFunctionResult g = new SpecialFunctionResult(); int stat_g = GammaXGTHalf(x, ref g); if (stat_g == PZMath_errno.PZMath_EOVRFLW) { PZMath_errno.UnderFlowError(ref result); } else { result.Val = 1.0 / g.Val; result.Err = System.Math.Abs(g.Err / g.Val) * System.Math.Abs(result.Val); result.Err += 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); PZMath_errno.CheckUnderFlow(result); return PZMath_errno.PZMath_SUCCESS; } } return PZMath_errno.PZMath_SUCCESS; }
/* series for gammastar(x) * double-precision for x > 10.0 */ public static int GammaStarSer(double x, ref SpecialFunctionResult result) { /* Use the Stirling series for the correction to Log(Gamma(x)), * which is better behaved and easier to compute than the * regular Stirling series for Gamma(x). */ double y = 1.0 / (x * x); double c0 = 1.0 / 12.0; double c1 = -1.0 / 360.0; double c2 = 1.0 / 1260.0; double c3 = -1.0 / 1680.0; double c4 = 1.0 / 1188.0; double c5 = -691.0 / 360360.0; double c6 = 1.0 / 156.0; double c7 = -3617.0 / 122400.0; double ser = c0 + y * (c1 + y * (c2 + y * (c3 + y * (c4 + y * (c5 + y * (c6 + y * c7)))))); result.Val = System.Math.Exp(ser / x); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * result.Val * System.Math.Max(1.0, ser / x); return PZMath_errno.PZMath_SUCCESS; }
public static int TaylorCoeffE(int n, double x, ref SpecialFunctionResult result) { if (x < 0.0 || n < 0) { PZMath_errno.DomainError(ref result); } else if (n == 0) { result.Val = 1.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (n == 1) { result.Val = x; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (x == 0.0) { result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else { double log2pi = PZMath.M_LNPI + PZMath.M_LN2; double ln_test = n * (System.Math.Log(x) + 1.0) + 1.0 - (n + 0.5) * System.Math.Log(n + 1.0) + 0.5 * log2pi; if (ln_test < PZMath_machine.PZMath_LOG_DBL_MIN + 1.0) { PZMath_errno.UnderFlowError(ref result); } else if (ln_test > PZMath_machine.PZMath_LOG_DBL_MAX - 1.0) { PZMath_errno.OverFlowError(ref result); } else { double product = 1.0; int k; for (k = 1; k <= n; k++) { product *= (x / k); } result.Val = product; result.Err = n * PZMath_machine.PZMath_DBL_EPSILON * product; PZMath_errno.CheckUnderFlow(result); return PZMath_errno.PZMath_SUCCESS; } } return PZMath_errno.PZMath_SUCCESS; }
public static int FactE(int n, ref SpecialFunctionResult result) { if (n < 18) { result.Val = fact_table[n]._f; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (n <= GSL_SF_FACT_NMAX) { result.Val = fact_table[n]._f; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { PZMath_errno.OverFlowError(ref result); } return PZMath_errno.PZMath_SUCCESS; }
/* Lanczos method for real x > 0; * gamma=7, truncated at 1/(z+8) * [J. SIAM Numer. Anal, Ser. B, 1 (1964) 86] */ public static int LnGammaLanczos(double x, ref SpecialFunctionResult result) { int k; double Ag; double term1, term2; x -= 1.0; /* Lanczos writes z! instead of Gamma(z) */ Ag = lanczos_7_c[0]; for (k = 1; k <= 8; k++) { Ag += lanczos_7_c[k] / (x + k); } /* (x+0.5)*System.Math.Log(x+7.5) - (x+7.5) + LogRootTwoPi_ + System.Math.Log(Ag(x)) */ term1 = (x + 0.5) * System.Math.Log((x + 7.5) / PZMath.M_E); term2 = LogRootTwoPi_ + System.Math.Log(Ag); result.Val = term1 + (term2 - 7.0); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * (System.Math.Abs(term1) + System.Math.Abs(term2) + 7.0); result.Err += PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; }
public static int LnGammaSgnE(double x, ref SpecialFunctionResult result_lg, ref double sgn) { if (System.Math.Abs(x - 1.0) < 0.01) { int stat = LnGamma1Pade(x - 1.0, ref result_lg); result_lg.Err *= 1.0 / (PZMath_machine.PZMath_DBL_EPSILON + System.Math.Abs(x - 1.0)); sgn = 1.0; return stat; } else if (System.Math.Abs(x - 2.0) < 0.01) { int stat = LnGamma2Pade(x - 2.0, ref result_lg); result_lg.Err *= 1.0 / (PZMath_machine.PZMath_DBL_EPSILON + System.Math.Abs(x - 2.0)); sgn = 1.0; return stat; } else if (x >= 0.5) { sgn = 1.0; return LnGammaLanczos(x, ref result_lg); } else if (x == 0.0) { sgn = 0.0; PZMath_errno.DomainError(ref result_lg); } else if (System.Math.Abs(x) < 0.02) { return LnGammaSgn0(x, ref result_lg, ref sgn); } else if (x > -0.5 / (PZMath_machine.PZMath_DBL_EPSILON * PZMath.M_PI)) { /* Try to extract a fractional * part from x. */ double z = 1.0 - x; double s = System.Math.Sin(PZMath.M_PI * x); double abss = System.Math.Abs(s); if (s == 0.0) { sgn = 0.0; PZMath_errno.DomainError(ref result_lg); } else if (abss < PZMath.M_PI * 0.015) { /* x is near a negative integer, -N */ if (x < int.MinValue + 2.0) { result_lg.Val = 0.0; result_lg.Err = 0.0; sgn = 0.0; PZMath_errno.ERROR("error", PZMath_errno.PZMath_EROUND); } else { int N = -(int)(x - 0.5); double eps = x + N; return LnGammaSgnSing(N, eps, ref result_lg, ref sgn); } } else { SpecialFunctionResult lg_z = new SpecialFunctionResult(); LnGammaLanczos(z, ref lg_z); sgn = (s > 0.0 ? 1.0 : -1.0); result_lg.Val = PZMath.M_LNPI - (System.Math.Log(abss) + lg_z.Val); result_lg.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result_lg.Val) + lg_z.Err; return PZMath_errno.PZMath_SUCCESS; } } else { /* |x| was too large to extract any fractional part */ result_lg.Val = 0.0; result_lg.Err = 0.0; sgn = 0.0; PZMath_errno.ERROR("error", PZMath_errno.PZMath_EROUND); } return PZMath_errno.PZMath_SUCCESS; }
public static int Zetam1E(double s, ref SpecialFunctionResult result) { if (s <= 5.0) { int stat = ZetaE(s, ref result); result.Val = result.Val - 1.0; return stat; } else if (s < 15.0) { return RiemannZetaMinus1IntermediateS(s, ref result); } else { return RiemannZetaMinus1LargeS(s, ref result); } }
public static int Zetam1IntE(int n, ref SpecialFunctionResult result) { if (n < 0) { if (!PZMath.IsOdd(n)) { result.Val = -1.0; /* at even negative integers zetam1 == -1 since zeta is exactly zero */ result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (n > -ZETA_NEG_TABLE_NMAX) { result.Val = zeta_neg_int_table[-(n + 1) / 2] - 1.0; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { /* could use gsl_sf_zetam1_e here but subtracting 1 makes no difference for such large values, so go straight to the result */ return ZetaE((double)n, ref result); } } else if (n == 1) { PZMath_errno.DomainError(ref result); } else if (n <= ZETA_POS_TABLE_NMAX) { result.Val = zetam1_pos_int_table[n]; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { return Zetam1E(n, ref result); } return PZMath_errno.PZMath_SUCCESS; }
public static int ZetaIntE(int n, ref SpecialFunctionResult result) { if (n < 0) { if (!PZMath.IsOdd(n)) { result.Val = 0.0; /* exactly zero at even negative integers */ result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (n > -ZETA_NEG_TABLE_NMAX) { result.Val = zeta_neg_int_table[-(n + 1) / 2]; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { return ZetaE((double)n, ref result); } } else if (n == 1) { PZMath_errno.DomainError(ref result); } else if (n <= ZETA_POS_TABLE_NMAX) { result.Val = 1.0 + zetam1_pos_int_table[n]; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { result.Val = 1.0; result.Err = PZMath_machine.PZMath_DBL_EPSILON; return PZMath_errno.PZMath_SUCCESS; } return PZMath_errno.PZMath_SUCCESS; }
public static int ZetaE(double s, ref SpecialFunctionResult result) { if (s == 1.0) { PZMath_errno.DomainError(ref result); } else if (s >= 0.0) { return RiemannZetaSgt0(s, ref result); } else { /* reflection formula, [Abramowitz+Stegun, 23.2.5] */ SpecialFunctionResult zeta_one_minus_s = new SpecialFunctionResult(); int stat_zoms = RiemannZeta1msSlt0(s, ref zeta_one_minus_s); double sin_term = (System.Math.IEEERemainder(s, 2.0) == 0.0) ? 0.0 : System.Math.Sin(0.5 * PZMath.M_PI * System.Math.IEEERemainder(s, 4.0)) / PZMath.M_PI; if (sin_term == 0.0) { result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (s > -170) { /* We have to be careful about losing digits * in calculating System.Math.Pow(2 Pi, s). The gamma * function is fine because we were careful * with that implementation. * We keep an array of (2 Pi)^(10 n). */ double[] twopi_pow = { 1.0, 9.589560061550901348e+007, 9.195966217409212684e+015, 8.818527036583869903e+023, 8.456579467173150313e+031, 8.109487671573504384e+039, 7.776641909496069036e+047, 7.457457466828644277e+055, 7.151373628461452286e+063, 6.857852693272229709e+071, 6.576379029540265771e+079, 6.306458169130020789e+087, 6.047615938853066678e+095, 5.799397627482402614e+103, 5.561367186955830005e+111, 5.333106466365131227e+119, 5.114214477385391780e+127, 4.904306689854036836e+135 }; int n = (int)System.Math.Floor((-s) / 10.0); double fs = s + 10.0 * n; double p = System.Math.Pow(2.0 * PZMath.M_PI, fs) / twopi_pow[n]; SpecialFunctionResult g = new SpecialFunctionResult(); int stat_g = Gamma.GammaE(1.0 - s, ref g); result.Val = p * g.Val * sin_term * zeta_one_minus_s.Val; result.Err = System.Math.Abs(p * g.Val * sin_term) * zeta_one_minus_s.Err; result.Err += System.Math.Abs(p * sin_term * zeta_one_minus_s.Val) * g.Err; result.Err += PZMath_machine.PZMath_DBL_EPSILON * (System.Math.Abs(s) + 2.0) * System.Math.Abs(result.Val); return PZMath_errno.ErrorSelect2(stat_g, stat_zoms); } else { /* The actual zeta function may or may not * overflow here. But we have no easy way * to calculate it when the prefactor(s) * overflow. Trying to use System.Math.Log's and exp * is no good because we loose a couple * digits to the exp error amplification. * When we gather a little more patience, * we can implement something here. Until * then just give up. */ PZMath_errno.OverFlowError(ref result); } } return PZMath_errno.PZMath_SUCCESS; }
/* assumes s >= 0 and s != 1.0 */ public static int RiemannZetaSgt0(double s, ref SpecialFunctionResult result) { if (s < 1.0) { SpecialFunctionResult c = new SpecialFunctionResult(); ChebyshevSeries.ChebEvalE(zeta_xlt1_cs, 2.0 * s - 1.0, ref c); result.Val = c.Val / (s - 1.0); result.Err = c.Err / System.Math.Abs(s - 1.0) + PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else if (s <= 20.0) { double x = (2.0 * s - 21.0) / 19.0; SpecialFunctionResult c = new SpecialFunctionResult(); ChebyshevSeries.ChebEvalE(zeta_xgt1_cs, x, ref c); result.Val = c.Val / (s - 1.0); result.Err = c.Err / (s - 1.0) + PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { double f2 = 1.0 - System.Math.Pow(2.0, -s); double f3 = 1.0 - System.Math.Pow(3.0, -s); double f5 = 1.0 - System.Math.Pow(5.0, -s); double f7 = 1.0 - System.Math.Pow(7.0, -s); result.Val = 1.0 / (f2 * f3 * f5 * f7); result.Err = 3.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } }
/* assumes s is large and positive * write: zeta(s) - 1 = zeta(s) * (1 - 1/zeta(s)) * and expand a few terms of the product formula to evaluate 1 - 1/zeta(s) * * works well for s > 15 */ public static int RiemannZetaMinus1LargeS(double s, ref SpecialFunctionResult result) { double a = System.Math.Pow(2.0, -s); double b = System.Math.Pow(3.0, -s); double c = System.Math.Pow(5.0, -s); double d = System.Math.Pow(7.0, -s); double e = System.Math.Pow(11.0, -s); double f = System.Math.Pow(13.0, -s); double t1 = a + b + c + d + e + f; double t2 = a * (b + c + d + e + f) + b * (c + d + e + f) + c * (d + e + f) + d * (e + f) + e * f; /* double t3 = a*(b*(c+d+e+f) + c*(d+e+f) + d*(e+f) + e*f) + b*(c*(d+e+f) + d*(e+f) + e*f) + c*(d*(e+f) + e*f) + d*e*f; double t4 = a*(b*(c*(d + e + f) + d*(e + f) + e*f) + c*(d*(e+f) + e*f) + d*e*f) + b*(c*(d*(e+f) + e*f) + d*e*f) + c*d*e*f; double t5 = b*c*d*e*f + a*c*d*e*f+ a*b*d*e*f+ a*b*c*e*f+ a*b*c*d*f+ a*b*c*d*e; double t6 = a*b*c*d*e*f; */ double numt = t1 - t2 /* + t3 - t4 + t5 - t6 */; double zeta = 1.0 / ((1.0 - a) * (1.0 - b) * (1.0 - c) * (1.0 - d) * (1.0 - e) * (1.0 - f)); result.Val = numt * zeta; result.Err = (15.0 / s + 1.0) * 6.0 * PZMath_machine.PZMath_DBL_EPSILON * result.Val; return PZMath_errno.PZMath_SUCCESS; }
/* works for 5 < s < 15*/ public static int RiemannZetaMinus1IntermediateS(double s, ref SpecialFunctionResult result) { double t = (s - 10.0) / 5.0; SpecialFunctionResult c = new SpecialFunctionResult(); ChebyshevSeries.ChebEvalE(zetam1_inter_cs, t, ref c); result.Val = System.Math.Exp(c.Val) + System.Math.Pow(2.0, -s); result.Err = (c.Err + 2.0 * PZMath_machine.PZMath_DBL_EPSILON) * result.Val; return PZMath_errno.PZMath_SUCCESS; }
/* x = eps near zero * gives double-precision for |eps| < 0.02 */ public static int LnGammaSgn0(double eps, ref SpecialFunctionResult lng, ref double sgn) { /* calculate series for g(eps) = Gamma(eps) eps - 1/(1+eps) - eps/2 */ double c1 = -0.07721566490153286061; double c2 = -0.01094400467202744461; double c3 = 0.09252092391911371098; double c4 = -0.01827191316559981266; double c5 = 0.01800493109685479790; double c6 = -0.00685088537872380685; double c7 = 0.00399823955756846603; double c8 = -0.00189430621687107802; double c9 = 0.00097473237804513221; double c10 = -0.00048434392722255893; double g6 = c6 + eps * (c7 + eps * (c8 + eps * (c9 + eps * c10))); double g = eps * (c1 + eps * (c2 + eps * (c3 + eps * (c4 + eps * (c5 + eps * g6))))); /* calculate Gamma(eps) eps, a positive quantity */ double gee = g + 1.0 / (1.0 + eps) + 0.5 * eps; lng.Val = System.Math.Log(gee / System.Math.Abs(eps)); lng.Err = 4.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(lng.Val); sgn = System.Math.Sign(eps); return PZMath_errno.PZMath_SUCCESS; }
public static int MultiplyErrE(double x, double dx, double y, double dy, ref SpecialFunctionResult result) { int status = MultiplyE(x, y, ref result); result.Err += System.Math.Abs(dx * y) + System.Math.Abs(dy * x); return status; }
/* x near a negative integer * Calculates sign as well as System.Math.Log(|gamma(x)|). * x = -N + eps * assumes N >= 1 */ public static int LnGammaSgnSing(int N, double eps, ref SpecialFunctionResult lng, ref double sgn) { if (eps == 0.0) { lng.Val = 0.0; lng.Err = 0.0; sgn = 0.0; PZMath_errno.ERROR("error", PZMath_errno.PZMath_EDOM); } else if (N == 1) { /* calculate series for * g = eps gamma(-1+eps) + 1 + eps/2 (1+3eps)/(1-eps^2) * double-precision for |eps| < 0.02 */ double c0 = 0.07721566490153286061; double c1 = 0.08815966957356030521; double c2 = -0.00436125434555340577; double c3 = 0.01391065882004640689; double c4 = -0.00409427227680839100; double c5 = 0.00275661310191541584; double c6 = -0.00124162645565305019; double c7 = 0.00065267976121802783; double c8 = -0.00032205261682710437; double c9 = 0.00016229131039545456; double g5 = c5 + eps * (c6 + eps * (c7 + eps * (c8 + eps * c9))); double g = eps * (c0 + eps * (c1 + eps * (c2 + eps * (c3 + eps * (c4 + eps * g5))))); /* calculate eps gamma(-1+eps), a negative quantity */ double gam_e = g - 1.0 - 0.5 * eps * (1.0 + 3.0 * eps) / (1.0 - eps * eps); lng.Val = System.Math.Log(System.Math.Abs(gam_e) / System.Math.Abs(eps)); lng.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(lng.Val); sgn = (eps > 0.0 ? -1.0 : 1.0); return PZMath_errno.PZMath_SUCCESS; } else { double g; /* series for System.Math.Sin(Pi(N+1-eps))/(Pi eps) modulo the sign * double-precision for |eps| < 0.02 */ double cs1 = -1.6449340668482264365; double cs2 = 0.8117424252833536436; double cs3 = -0.1907518241220842137; double cs4 = 0.0261478478176548005; double cs5 = -0.0023460810354558236; double e2 = eps * eps; double sin_ser = 1.0 + e2 * (cs1 + e2 * (cs2 + e2 * (cs3 + e2 * (cs4 + e2 * cs5)))); /* calculate series for ln(gamma(1+N-eps)) * double-precision for |eps| < 0.02 */ double aeps = System.Math.Abs(eps); double c1, c2, c3, c4, c5, c6, c7; double lng_ser; SpecialFunctionResult c0 = new SpecialFunctionResult(); SpecialFunctionResult psi_0 = new SpecialFunctionResult(); SpecialFunctionResult psi_1 = new SpecialFunctionResult(); SpecialFunctionResult psi_2 = new SpecialFunctionResult(); SpecialFunctionResult psi_3 = new SpecialFunctionResult(); SpecialFunctionResult psi_4 = new SpecialFunctionResult(); SpecialFunctionResult psi_5 = new SpecialFunctionResult(); SpecialFunctionResult psi_6 = new SpecialFunctionResult(); psi_2.Val = 0.0; psi_3.Val = 0.0; psi_4.Val = 0.0; psi_5.Val = 0.0; psi_6.Val = 0.0; LnFactE(N, ref c0); Psi.PsiIntE(N + 1, ref psi_0); Psi.Psi1IntE(N + 1, ref psi_1); if (aeps > 0.00001) Psi.PsiNE(2, N + 1.0, ref psi_2); if (aeps > 0.0002) Psi.PsiNE(3, N + 1.0, ref psi_3); if (aeps > 0.001) Psi.PsiNE(4, N + 1.0, ref psi_4); if (aeps > 0.005) Psi.PsiNE(5, N + 1.0, ref psi_5); if (aeps > 0.01) Psi.PsiNE(6, N + 1.0, ref psi_6); c1 = psi_0.Val; c2 = psi_1.Val / 2.0; c3 = psi_2.Val / 6.0; c4 = psi_3.Val / 24.0; c5 = psi_4.Val / 120.0; c6 = psi_5.Val / 720.0; c7 = psi_6.Val / 5040.0; lng_ser = c0.Val - eps * (c1 - eps * (c2 - eps * (c3 - eps * (c4 - eps * (c5 - eps * (c6 - eps * c7)))))); /* calculate * g = ln(|eps gamma(-N+eps)|) * = -ln(gamma(1+N-eps)) + ln(|eps Pi/System.Math.Sin(Pi(N+1+eps))|) */ g = -lng_ser - System.Math.Log(sin_ser); lng.Val = g - System.Math.Log(System.Math.Abs(eps)); lng.Err = c0.Err + 2.0 * PZMath_machine.PZMath_DBL_EPSILON * (System.Math.Abs(g) + System.Math.Abs(lng.Val)); sgn = (PZMath.IsOdd(N) ? -1.0 : 1.0) * (eps > 0.0 ? 1.0 : -1.0); return PZMath_errno.PZMath_SUCCESS; } return PZMath_errno.PZMath_SUCCESS; }
public static int LnChooseE(int n, int m, ref SpecialFunctionResult result) { /* CHECK_POINTER(result) */ if (m > n) { PZMath_errno.DomainError(ref result); } else if (m == n || m == 0) { result.Val = 0.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else { SpecialFunctionResult nf = new SpecialFunctionResult(); SpecialFunctionResult mf = new SpecialFunctionResult(); SpecialFunctionResult nmmf = new SpecialFunctionResult(); if (m * 2 > n) m = n - m; LnFactE(n, ref nf); LnFactE(m, ref mf); LnFactE(n - m, ref nmmf); result.Val = nf.Val - mf.Val - nmmf.Val; result.Err = nf.Err + mf.Err + nmmf.Err; result.Err += 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } return PZMath_errno.PZMath_SUCCESS; }
public static int ChooseE(int n, int m, ref SpecialFunctionResult result) { if (m > n) { PZMath_errno.DomainError(ref result); } else if (m == n || m == 0) { result.Val = 1.0; result.Err = 0.0; return PZMath_errno.PZMath_SUCCESS; } else if (n <= GSL_SF_FACT_NMAX) { result.Val = (fact_table[n]._f / fact_table[m]._f) / fact_table[n - m]._f; result.Err = 6.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { if (m * 2 < n) m = n - m; if (n - m < 64) /* compute product for a manageable number of terms */ { double prod = 1.0; int k; for (k = n; k >= m + 1; k--) { double tk = (double)k / (double)(k - m); if (tk > PZMath_machine.PZMath_DBL_MAX / prod) { PZMath_errno.OverFlowError(ref result); } prod *= tk; } result.Val = prod; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * prod * System.Math.Abs(n - m); return PZMath_errno.PZMath_SUCCESS; } else { SpecialFunctionResult lc = new SpecialFunctionResult(); int stat_lc = LnChooseE(n, m, ref lc); int stat_e = Exp.ExpErrE(lc.Val, lc.Err, ref result); return PZMath_errno.ErrorSelect2(stat_lc, stat_e); } } return PZMath_errno.PZMath_SUCCESS; }
public static int LnDoubleFactE(int n, ref SpecialFunctionResult result) { if (n <= GSL_SF_DOUBLEFACT_NMAX) { result.Val = System.Math.Log(doub_fact_table[n]._f); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else if (PZMath.IsOdd(n)) { SpecialFunctionResult lg = new SpecialFunctionResult(); LnGammaE(0.5 * (n + 2.0), ref lg); result.Val = 0.5 * (n + 1.0) * PZMath.M_LN2 - 0.5 * PZMath.M_LNPI + lg.Val; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val) + lg.Err; return PZMath_errno.PZMath_SUCCESS; } else { SpecialFunctionResult lg = new SpecialFunctionResult(); LnGammaE(0.5 * n + 1.0, ref lg); result.Val = 0.5 * n * PZMath.M_LN2 + lg.Val; result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val) + lg.Err; return PZMath_errno.PZMath_SUCCESS; } }
public static int GammaE(double x, ref SpecialFunctionResult result) { if (x < 0.5) { int rint_x = (int)System.Math.Floor(x + 0.5); double f_x = x - rint_x; double sgn_gamma = (PZMath.IsEven(rint_x) ? 1.0 : -1.0); double sin_term = sgn_gamma * System.Math.Sin(PZMath.M_PI * f_x) / PZMath.M_PI; if (sin_term == 0.0) { PZMath_errno.DomainError(ref result); } else if (x > -169.0) { SpecialFunctionResult g = new SpecialFunctionResult(); GammaXGTHalf(1.0 - x, ref g); if (System.Math.Abs(sin_term) * g.Val * PZMath_machine.PZMath_DBL_MIN < 1.0) { result.Val = 1.0 / (sin_term * g.Val); result.Err = System.Math.Abs(g.Err / g.Val) * System.Math.Abs(result.Val); result.Err += 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { PZMath_errno.UnderFlowError(ref result); } } else { /* It is hard to control it here. * We can only exponentiate the * logarithm and eat the loss of * precision. */ SpecialFunctionResult lng = new SpecialFunctionResult(); double sgn = 0.0; int stat_lng = LnGammaSgnE(x, ref lng, ref sgn); int stat_e = Exp.ExpMultErrE(lng.Val, lng.Err, sgn, 0.0, ref result); return PZMath_errno.ErrorSelect2(stat_e, stat_lng); } } else { return GammaXGTHalf(x, ref result); } return PZMath_errno.PZMath_SUCCESS; }
public static int LnFactE(int n, ref SpecialFunctionResult result) { /* CHECK_POINTER(result) */ if (n <= GSL_SF_FACT_NMAX) { result.Val = System.Math.Log(fact_table[n]._f); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { LnGammaE(n + 1.0, ref result); return PZMath_errno.PZMath_SUCCESS; } }
public static int GammaStarE(double x, ref SpecialFunctionResult result) { if (x <= 0.0) { PZMath_errno.DomainError(ref result); } else if (x < 0.5) { SpecialFunctionResult lg = new SpecialFunctionResult(); int stat_lg = LnGammaE(x, ref lg); double lx = System.Math.Log(x); double c = 0.5 * (PZMath.M_LN2 + PZMath.M_LNPI); double lnr_val = lg.Val - (x - 0.5) * lx + x - c; double lnr_err = lg.Err + 2.0 * PZMath_machine.PZMath_DBL_EPSILON * ((x + 0.5) * System.Math.Abs(lx) + c); int stat_e = Exp.ExpErrE(lnr_val, lnr_err, ref result); return PZMath_errno.ErrorSelect2(stat_lg, stat_e); } else if (x < 2.0) { double t = 4.0 / 3.0 * (x - 0.5) - 1.0; return ChebyshevSeries.ChebEvalE(gstar_a_cs, t, ref result); } else if (x < 10.0) { double t = 0.25 * (x - 2.0) - 1.0; SpecialFunctionResult c = new SpecialFunctionResult(); ChebyshevSeries.ChebEvalE(gstar_b_cs, t, ref c); result.Val = c.Val / (x * x) + 1.0 + 1.0 / (12.0 * x); result.Err = c.Err / (x * x); result.Err += 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else if (x < 1.0 / PZMath_machine.PZMath_ROOT4_DBL_EPSILON) { return GammaStarSer(x, ref result); } else if (x < 1.0 / PZMath_machine.PZMath_DBL_EPSILON) { /* Use Stirling formula for Gamma(x). */ double xi = 1.0 / x; result.Val = 1.0 + xi / 12.0 * (1.0 + xi / 24.0 * (1.0 - xi * (139.0 / 180.0 + 571.0 / 8640.0 * xi))); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; } else { result.Val = 1.0; result.Err = 1.0 / x; return PZMath_errno.PZMath_SUCCESS; } return PZMath_errno.PZMath_SUCCESS; }
/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/ public static double LnGamma(double x) { SpecialFunctionResult result = new SpecialFunctionResult(); LnGammaE(x, ref result); return result.Val; }
/* gamma(x) for x >= 1/2 * assumes x >= 1/2 */ public static int GammaXGTHalf(double x, ref SpecialFunctionResult result) { if (x == 0.5) { result.Val = 1.77245385090551602729817; result.Err = PZMath_machine.PZMath_DBL_EPSILON * result.Val; return PZMath_errno.PZMath_SUCCESS; } else if (x <= (GSL_SF_FACT_NMAX + 1.0) && x == System.Math.Floor(x)) { int n = (int)System.Math.Floor(x); result.Val = fact_table[n - 1]._f; result.Err = PZMath_machine.PZMath_DBL_EPSILON * result.Val; return PZMath_errno.PZMath_SUCCESS; } else if (System.Math.Abs(x - 1.0) < 0.01) { /* Use series for Gamma[1+eps] - 1/(1+eps). */ double eps = x - 1.0; double c1 = 0.4227843350984671394; double c2 = -0.01094400467202744461; double c3 = 0.09252092391911371098; double c4 = -0.018271913165599812664; double c5 = 0.018004931096854797895; double c6 = -0.006850885378723806846; double c7 = 0.003998239557568466030; result.Val = 1.0 / x + eps * (c1 + eps * (c2 + eps * (c3 + eps * (c4 + eps * (c5 + eps * (c6 + eps * c7)))))); result.Err = PZMath_machine.PZMath_DBL_EPSILON; return PZMath_errno.PZMath_SUCCESS; } else if (System.Math.Abs(x - 2.0) < 0.01) { /* Use series for Gamma[1 + eps]. */ double eps = x - 2.0; double c1 = 0.4227843350984671394; double c2 = 0.4118403304264396948; double c3 = 0.08157691924708626638; double c4 = 0.07424901075351389832; double c5 = -0.00026698206874501476832; double c6 = 0.011154045718130991049; double c7 = -0.002852645821155340816; double c8 = 0.0021039333406973880085; result.Val = 1.0 + eps * (c1 + eps * (c2 + eps * (c3 + eps * (c4 + eps * (c5 + eps * (c6 + eps * (c7 + eps * c8))))))); result.Err = PZMath_machine.PZMath_DBL_EPSILON; return PZMath_errno.PZMath_SUCCESS; } else if (x < 5.0) { /* Exponentiating the logarithm is fine, as * long as the exponential is not so large * that it greatly amplifies the error. */ SpecialFunctionResult lg = new SpecialFunctionResult(); LnGammaLanczos(x, ref lg); result.Val = System.Math.Exp(lg.Val); result.Err = result.Val * (lg.Err + 2.0 * PZMath_machine.PZMath_DBL_EPSILON); return PZMath_errno.PZMath_SUCCESS; } else if (x < 10.0) { /* This is a sticky area. The logarithm * is too large and the gammastar series * is not good. */ double gamma_8 = 5040.0; double t = (2.0 * x - 15.0) / 5.0; SpecialFunctionResult c = new SpecialFunctionResult(); ChebyshevSeries.ChebEvalE(gamma_5_10_cs, t, ref c); result.Val = System.Math.Exp(c.Val) * gamma_8; result.Err = result.Val * c.Err; result.Err += 2.0 * PZMath_machine.PZMath_DBL_EPSILON * result.Val; return PZMath_errno.PZMath_SUCCESS; } else if (x < GSL_SF_GAMMA_XMAX) { /* We do not want to exponentiate the logarithm * if x is large because of the inevitable * inflation of the error. So we carefully * use System.Math.Pow() and System.Math.Exp() with exact quantities. */ double p = System.Math.Pow(x, 0.5 * x); double e = System.Math.Exp(-x); double q = (p * e) * p; double pre = PZMath.M_SQRT2 * PZMath.M_SQRTPI * q / System.Math.Sqrt(x); SpecialFunctionResult gstar = new SpecialFunctionResult(); int stat_gs = GammaStarSer(x, ref gstar); result.Val = pre * gstar.Val; result.Err = (x + 2.5) * PZMath_machine.PZMath_DBL_EPSILON * result.Val; return stat_gs; } else { PZMath_errno.OverFlowError(ref result); } return PZMath_errno.PZMath_SUCCESS; }
public static int LnGamma1Pade(double eps, ref SpecialFunctionResult result) { /* Use (2,2) Pade for Log[Gamma[1+eps]]/eps * plus a correction series. */ double n1 = -1.0017419282349508699871138440; double n2 = 1.7364839209922879823280541733; double d1 = 1.2433006018858751556055436011; double d2 = 5.0456274100274010152489597514; double num = (eps + n1) * (eps + n2); double den = (eps + d1) * (eps + d2); double pade = 2.0816265188662692474880210318 * num / den; double c0 = 0.004785324257581753; double c1 = -0.01192457083645441; double c2 = 0.01931961413960498; double c3 = -0.02594027398725020; double c4 = 0.03141928755021455; double eps5 = eps * eps * eps * eps * eps; double corr = eps5 * (c0 + eps * (c1 + eps * (c2 + eps * (c3 + c4 * eps)))); result.Val = eps * (pade + corr); result.Err = 2.0 * PZMath_machine.PZMath_DBL_EPSILON * System.Math.Abs(result.Val); return PZMath_errno.PZMath_SUCCESS; }