Пример #1
0
        private static double HypergeometricHYP(PRNG prng, double good, double bad, long sample)
        {
            var d1 = bad + good - sample;
            var d2 = Convert.ToDouble(Math.Min(bad, good));
            var Y  = d2;
            var K  = sample;

            while (Y > 0.0)
            {
                var U = prng.Draw();
                Y -= Math.Floor(U + Y / (d1 + K));
                K -= 1;
                if (K == 0)
                {
                    break;
                }
            }
            var Z = Math.Floor(d2 - Y);

            if (good > bad)
            {
                Z = sample - Z;
            }
            return(Z);
        }
Пример #2
0
        private static double HypergeometricHRUA(PRNG prng, double good, double bad, long sample)
        {
            var    D1         = 1.7155277699214135;
            var    D2         = 0.8989161620588988;
            var    minGoodBad = Math.Min(good, bad);
            var    popSize    = good + bad;
            var    maxGoodBad = Math.Max(good, bad);
            var    m          = Math.Min(sample, popSize - sample);
            var    d4         = minGoodBad / popSize;
            var    d5         = 1.0 - d4;
            var    d6         = m * d4 + 0.5;
            var    d7         = Math.Sqrt((popSize - m) * sample * d4 * d5 / (popSize - 1) + 0.5);
            var    d8         = D1 * d7 + D2;
            var    d9         = Math.Floor(((double)m + 1) * (minGoodBad + 1) / (popSize + 2));
            var    d10        = LogGamma(d9 + 1) + LogGamma(minGoodBad - d9 + 1) + LogGamma(m - d9 + 1) + LogGamma(maxGoodBad - m + d9 + 1);
            var    d11        = Math.Min(Math.Min(m, minGoodBad) + 1.0, Math.Floor(d6 + 16 * d7));
            double Z;

            while (true)
            {
                var X = prng.Draw();
                var Y = prng.Draw();
                var W = d6 + d8 * (Y - 0.5) / X;
                if (W < 0.0 || W >= d11)
                {
                    continue;
                }
                Z = Math.Floor(W);
                var T = d10 - (LogGamma(Z + 1) + LogGamma(minGoodBad - Z + 1) + LogGamma(m - Z + 1) + LogGamma(maxGoodBad - m + Z + 1));
                if ((X * (4.0 - X) - 3.0) <= T)
                {
                    break;
                }
                if (X * (X - T) >= 1)
                {
                    continue;
                }
                if (2.0 * Math.Log(X) <= T)
                {
                    break;
                }
            }
            if (good > bad)
            {
                Z = m - Z;
            }
            if (m < sample)
            {
                Z = good - Z;
            }
            return(Z);
        }
Пример #3
0
        /*
         *  Random variates from the hypergeometric distribution.
         *
         *  Returns the number of white balls drawn when kk balls
         *  are drawn at random from an urn containing nn1 white
         *  and nn2 black balls.
         */
        private static double RHyper(long kk, double nn1, double nn2, CoinFlipper coins)
        {
            var prng = new PRNG(coins);

            if (kk > 10)
            {
                return(HypergeometricHRUA(prng, nn1, nn2, kk));
            }
            else
            {
                return(HypergeometricHYP(prng, nn1, nn2, kk));
            }
        }