Beispiel #1
0
        public override double NextDouble()
        {
            // algorithm GD for A >= 1
            if (algorithmGD)
            {
                const double
                // coefficients a(k) for q = q0+(t*t/2)*sum(a(k)*v**k)
                    a1 = 0.3333333,
                    a2 = -0.250003,
                    a3 = 0.2000062,
                    a4 = -0.1662921,
                    a5 = 0.1423657,
                    a6 = -0.1367177,
                    a7 = 0.1233795,
                // coefficients e(k) for exp(q)-1 = sum(e(k)*q**k)
                    e1 = 1.0,
                    e2 = 0.4999897,
                    e3 = 0.166829,
                    e4 = 4.07753E-2,
                    e5 = 1.0293E-2;

                double q, w, gamdis;

                // standard normal deviate
                double t = normalDistribution.NextDouble(); // original  this->NormalDistribution::operator()();

                // (s,1/2)-normal deviate
                double x = s + 0.5 * t;

                // immediate acceptance
                gamdis = x * x;
                if (t >= 0.0)
                {
                    return(gamdis / _invTheta);
                }

                // (0,1) uniform sample, squeeze acceptance
                double u = normalDistribution.Generator.Next() * scale; // original NormalDistribution::gen->Long() * scale;
                if (d * u <= t * t * t)
                {
                    return(gamdis / _invTheta);
                }

                // no quotient test if x not positive
                if (x > 0.0)
                {
                    // calculation of v and quotient q
                    double vv = t / (s + s);
                    if (Math.Abs(vv) <= 0.25)
                    {
                        q = q0 + 0.5 * t * t * ((((((a7 * vv + a6) * vv + a5) * vv + a4) * vv + a3) * vv + a2) * vv + a1) * vv;
                    }
                    else
                    {
                        q = q0 - s * t + 0.25 * t * t + (s2 + s2) * Math.Log(1.0 + vv);
                    }

                    // quotient acceptance
                    if (Math.Log(1.0 - u) <= q)
                    {
                        return(gamdis / _invTheta);
                    }
                }

loop:

// stdandard exponential deviate
                double e = exponentialDistribution.NextDouble(); // original this->ExponentialDistribution::operator()();

                // (0,1) uniform deviate
                u = normalDistribution.Generator.Next() * scale; // NormalDistribution::gen->Long() * scale;

                u += (u - 1.0);

                // (b,si) double exponential (Laplace)
                t = b + CopySign(si * e, u);

                // rejection if t < tau(1) = -0.71874483771719
                if (t < -0.71874483771719)
                {
                    goto loop;
                }

                // calculation of v and quotient q
                double v = t / (s + s);
                if (Math.Abs(v) <= 0.25)
                {
                    q = q0 + 0.5 * t * t * ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v;
                }
                else
                {
                    q = q0 - s * t + 0.25 * t * t + (s2 + s2) * Math.Log(1.0 + v);
                }

                // hat acceptance
                if (q <= 0.0)
                {
                    goto loop;
                }

                if (q <= 0.5)
                {
                    w = ((((e5 * q + e4) * q + e3) * q + e2) * q + e1) * q;
                }
                else
                {
                    w = Math.Exp(q) - 1.0;
                }

                // if t is rejected, sample again
                if (c * Math.Abs(u) > w * Math.Exp(e - 0.5 * t * t))
                {
                    goto loop;
                }

                x      = s + 0.5 * t;
                gamdis = x * x;
                return(gamdis / _invTheta);

                // algorithm GS for 0 < A < 1
            }
            else
            {
                double gamdis;
                for (; ;)
                {
                    double p = b * normalDistribution.Generator.Next() * scale;
                    if (p < 1.0)
                    {
                        gamdis = Math.Exp(Math.Log(p) / alpha);
                        if (exponentialDistribution.NextDouble() >= gamdis)
                        {
                            return(gamdis / _invTheta);
                        }
                    }
                    else
                    {
                        gamdis = -Math.Log((b - p) / alpha);
                        if (exponentialDistribution.NextDouble() >= (1.0 - alpha) * Math.Log(gamdis))
                        {
                            return(gamdis / _invTheta);
                        }
                    }
                } // for
            }
        }