/// <summary>
        /// Get the next sample point from the gaussian distribution.
        /// </summary>
        public double NextDouble()
        {
            if (null != _spareValue)
            {
                double tmp = _spareValue.Value;
                _spareValue = null;
                return(tmp);
            }

            // Generate two new gaussian values.
            double x, y, sqr;

            // We need a non-zero random point inside the unit circle.
            do
            {
                x   = 2.0 * _rng.NextDouble() - 1.0;
                y   = 2.0 * _rng.NextDouble() - 1.0;
                sqr = x * x + y * y;
            }while(sqr > 1.0 || sqr == 0);

            // Make the Box-Muller transformation.
            double fac = Math.Sqrt(-2.0 * Math.Log(sqr) / sqr);

            _spareValue = x * fac;
            return(y * fac);
        }
        /// <summary>
        /// Sample from the provided discrete probability distribution.
        /// </summary>
        /// <param name="dist">The discrete distribution to sample from.</param>
        /// <param name="rng">Random number generator.</param>
        public static int Sample(DiscreteDistribution dist, XorShiftRandom rng)
        {
            // Throw the ball and return an integer indicating the outcome.
            double sample = rng.NextDouble();
            double acc    = 0.0;

            for (int i = 0; i < dist.Probabilities.Length; i++)
            {
                acc += dist.Probabilities[i];
                if (sample < acc)
                {
                    return(dist.Labels[i]);
                }
            }

            // We might get here through floating point arithmetic rounding issues.
            // e.g. accumulator == throwValue.

            // Find a nearby non-zero probability to select.
            // Wrap around to start of array.
            for (int i = 0; i < dist.Probabilities.Length; i++)
            {
                if (0.0 != dist.Probabilities[i])
                {
                    return(dist.Labels[i]);
                }
            }

            // If we get here then we have an array of zero probabilities.
            throw new InvalidOperationException("Invalid operation. No non-zero probabilities to select.");
        }
示例#3
0
        /// <summary>
        /// Rounds up or down to a whole number by using the fractional part of the input value
        /// as the probability that the value will be rounded up.
        ///
        /// This is useful if we wish to round values and then sum them without generating a rounding bias.
        /// For monetary rounding this problem is solved with rounding to e.g. the nearest even number which
        /// then causes a bias towards even numbers.
        ///
        /// This solution is more appropriate for certain types of scientific values.
        /// </summary>
        public static double ProbabilisticRound(double val, XorShiftRandom rng)
        {
            double integerPart    = Math.Floor(val);
            double fractionalPart = val - integerPart;

            return(rng.NextDouble() < fractionalPart ? integerPart + 1.0 : integerPart);
        }
示例#4
0
        /// <summary>
        /// Get the next sample value from the gaussian distribution.
        /// </summary>
        public double NextSample()
        {
            for (;;)
            {
                // Select box at random.
                byte   u    = _rng.NextByte();
                int    i    = (int)(u & 0x7F);
                double sign = ((u & 0x80) == 0) ? -1.0 : 1.0;

                // Generate uniform random value with range [0,0xffffffff].
                uint u2 = _rng.NextUInt();

                // Special case for the base segment.
                if (0 == i)
                {
                    if (u2 < _xComp[0])
                    {   // Generated x is within R0.
                        return(u2 * __UIntToU * _A_Div_Y0 * sign);
                    }
                    // Generated x is in the tail of the distribution.
                    return(SampleTail() * sign);
                }

                // All other segments.
                if (u2 < _xComp[i])
                {   // Generated x is within the rectangle.
                    return(u2 * __UIntToU * _x[i] * sign);
                }

                // Generated x is outside of the rectangle.
                // Generate a random y coordinate and test if our (x,y) is within the distribution curve.
                // This execution path is relatively slow/expensive (makes a call to Math.Exp()) but relatively rarely executed,
                // although more often than the 'tail' path (above).
                double x = u2 * __UIntToU * _x[i];
                if (_y[i - 1] + ((_y[i] - _y[i - 1]) * _rng.NextDouble()) < GaussianPdfDenorm(x))
                {
                    return(x * sign);
                }
            }
        }
 /// <summary>
 /// Sample from a set of possible outcomes with equal probability, i.e. a uniform discrete distribution.
 /// </summary>
 /// <param name="numberOfOutcomes">The number of possible outcomes.</param>
 /// <param name="rng">Random number generator.</param>
 /// <returns>An integer between 0..numberOfOutcomes-1.</returns>
 public static int SampleUniformDistribution(int numberOfOutcomes, XorShiftRandom rng)
 {
     return((int)(rng.NextDouble() * numberOfOutcomes));
 }
 /// <summary>
 /// Sample from a binary distribution with the specified probability split between state false and true.
 /// </summary>
 /// <param name="probability">A probability between 0..1 that describes the probbaility of sampling boolean true.</param>
 /// <param name="rng">Random number generator.</param>
 public static bool SampleBinaryDistribution(double probability, XorShiftRandom rng)
 {
     return(rng.NextDouble() < probability);
 }