public void DistributionCentralMomentIntegral() { foreach (ContinuousDistribution distribution in distributions) { foreach (int n in TestUtilities.GenerateIntegerValues(2, 24, 8)) { // get the predicted central moment double C = distribution.CentralMoment(n); // don't try to integrate infinite moments if (Double.IsInfinity(C) || Double.IsNaN(C)) { continue; } if (C == 0.0) { continue; } IntegrationSettings settings = new IntegrationSettings(); if (C == 0.0) { // if moment is zero, use absolute precision settings.AbsolutePrecision = TestUtilities.TargetPrecision; settings.RelativePrecision = 0.0; } else { // if moment in non-zero, use relative precision settings.AbsolutePrecision = 0.0; settings.RelativePrecision = TestUtilities.TargetPrecision; } // do the integral double m = distribution.Mean; Func <double, double> f = delegate(double x) { return(distribution.ProbabilityDensity(x) * MoreMath.Pow(x - m, n)); }; try { double CI = FunctionMath.Integrate(f, distribution.Support, settings).Value; Console.WriteLine("{0} {1} {2} {3}", distribution.GetType().Name, n, C, CI); if (C == 0.0) { Assert.IsTrue(Math.Abs(CI) < TestUtilities.TargetPrecision); } else { double e = TestUtilities.TargetPrecision; // reduce required precision, because some distributions (e.g. Kolmogorov, Weibull) // have no analytic expressions for central moments, which must therefore be // determined via raw moments and are thus subject to cancelation error // can we revisit this later? if (distribution is WeibullDistribution) { e = Math.Sqrt(Math.Sqrt(e)); } if (distribution is KolmogorovDistribution) { e = Math.Sqrt(e); } if (distribution is KuiperDistribution) { e = Math.Sqrt(Math.Sqrt(e)); } if (distribution is TriangularDistribution) { e = Math.Sqrt(e); } Assert.IsTrue(TestUtilities.IsNearlyEqual(C, CI, e)); } } catch (NonconvergenceException) { Console.WriteLine("{0} {1} {2} {3}", distribution.GetType().Name, n, C, "NC"); // deal with these later; they are integration problems, not distribution problems } } } }