// Thanks to John D. Cook (johndcook.com) for this public domain random variate code // Get normal (Gaussian) random sample with specified mean and standard deviation static double GetNormal(double mean = 0.0, double standardDeviation = 1.0) { if (standardDeviation <= 0.0) { StnSciScenario.LogWarning("Invalid standard deviation: " + standardDeviation); return(0); } // Use Box-Muller algorithm double u1 = GetUniform(); double u2 = GetUniform(); double r = Math.Sqrt(-2.0 * Math.Log(u1)); double theta = 2.0 * Math.PI * u2; return(mean + standardDeviation * r * Math.Sin(theta)); }
static double GetGamma(double shape, double scale) { // Implementation based on "A Simple Method for Generating Gamma Variables" // by George Marsaglia and Wai Wan Tsang. ACM Transactions on Mathematical Software // Vol 26, No 3, September 2000, pages 363-372. double d, c, x, xsquared, v, u; if (shape >= 1.0) { d = shape - 1.0 / 3.0; c = 1.0 / Math.Sqrt(9.0 * d); for (;;) { do { x = GetNormal(); v = 1.0 + c * x; }while (v <= 0.0); v = v * v * v; u = GetUniform(); xsquared = x * x; if (u < 1.0 - .0331 * xsquared * xsquared || Math.Log(u) < 0.5 * xsquared + d * (1.0 - v + Math.Log(v))) { return(scale * d * v); } } } else if (shape <= 0.0) { StnSciScenario.LogWarning("Invalid Gamma shape: " + shape); return(0); } else { double g = GetGamma(shape + 1.0, 1.0); double w = GetUniform(); return(scale * g * Math.Pow(w, 1.0 / shape)); } }