Пример #1
0
        /// <summary>
        /// Returns a random value sampled from the standard Gaussian distribution, i.e., with mean of 0 and standard deviation of 1.
        /// </summary>
        /// <param name="rng">Random source.</param>
        /// <returns>A new random sample.</returns>
        public static float Sample(IRandomSource rng)
        {
            for (;;)
            {
                // Generate 64 random bits.
                ulong u = rng.NextULong();

                // Note. 32 random bits are required and therefore the lowest 32 bits are discarded
                // (a typical characteristic of PRNGs is that the least significant bits exhibit lower
                // quality randomness than the higher bits).
                // Select a segment (7 bits, bits 32 to 38).
                int s = (int)((u >> 32) & 0x7f);

                // Select the sign bit (bit 39), and convert to a single-precision float value of -1.0 or +1.0 accordingly.
                // Notes.
                // Here we convert the single chosen bit directly into IEEE754 single-precision floating-point format.
                // Previously this conversion used a branch, which is considerably slower because modern superscalar
                // CPUs rely heavily on branch prediction, but the outcome of this branch is pure random noise and thus
                // entirely unpredictable, i.e. the absolute worse case scenario!
                float sign = BitConverter.Int32BitsToSingle(unchecked ((int)(((u & 0x80_0000_0000UL) >> 8) | __oneBits)));

                // Get a uniform random value with interval [0, 2^24-1], or in hexadecimal [0, 0xff_ffff]
                // (i.e. a random 24 bit number) (bits 40 to 63).
                ulong u2 = u >> 40;

                // Special case for the base segment.
                if (s == 0)
                {
                    if (u2 < __xComp[0])
                    {
                        // Generated x is within R0.
                        return(u2 * __INCR * __A_Div_Y0 * sign);
                    }
                    // Generated x is in the tail of the distribution.
                    return(SampleTail(rng) * sign);
                }

                // All other segments.
                if (u2 < __xComp[s])
                {
                    // Generated x is within the rectangle.
                    return(u2 * __INCR * __x[s] * 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 is relatively rarely executed,
                // although more often than the 'tail' path (above).
                float x = u2 * __INCR * __x[s];
                if (__y[s - 1] + ((__y[s] - __y[s - 1]) * rng.NextFloat()) < GaussianPdfDenormF(x))
                {
                    return(x * sign);
                }
            }
        }
        /// <summary>
        /// Take a sample from the standard gaussian distribution, i.e. with mean of 0 and standard deviation of 1.
        /// </summary>
        public double SampleStandard()
        {
            for (;;)
            {
                // Generate 64 random bits.
                ulong u = _rng.NextULong();

                // Notes. We require 61 of the random bits in total so we discard the lowest three bits because these
                // generally exhibit lower quality randomness than the higher bits (depending on the PRNG is use, but
                // it is a common feature of many PRNGs).

                // Select a segment (7 bits, bits 3 to 9).
                int s = (int)((u >> 3) & 0x7f);

                // Select sign bit (bit 10).
                double sign = ((u & 0x400) == 0) ? 1.0 : -1.0;

                // Get a uniform random value with interval [0, 2^53-1], or in hexadecimal [0, 0x1f_ffff_ffff_ffff]
                // (i.e. a random 53 bit number) (bits 11 to 63).
                ulong u2 = u >> 11;

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

                // All other segments.
                if (u2 < _xComp[s])
                {
                    // Generated x is within the rectangle.
                    return(u2 * __INCR * _x[s] * 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 is relatively rarely executed,
                // although more often than the 'tail' path (above).
                double x = u2 * __INCR * _x[s];
                if (_y[s - 1] + ((_y[s] - _y[s - 1]) * _rng.NextDouble()) < GaussianPdfDenorm(x))
                {
                    return(x * sign);
                }
            }
        }
        /// <summary>
        /// Take a sample from the standard Gaussian distribution, i.e. with mean of 0 and standard deviation of 1.
        /// </summary>
        /// <returns>A random sample.</returns>
        public static double Sample(this IRandomSource rng)
        {
            for (; ;)
            {
                // Generate 64 random bits.
                ulong u = rng.NextULong();

                // Note. 61 random bits are required and therefore the lowest three bits are discarded
                // (a typical characteristic of PRNGs is that the least significant bits exhibit lower
                // quality randomness than the higher bits).
                // Select a segment (7 bits, bits 3 to 9).
                int s = (int)((u >> 3) & 0x7f);

                // Select sign bit (bit 10).
                double sign = ((u & 0x400) == 0) ? 1.0 : -1.0;

                // Get a uniform random value with interval [0, 2^53-1], or in hexadecimal [0, 0x1f_ffff_ffff_ffff]
                // (i.e. a random 53 bit number) (bits 11 to 63).
                ulong u2 = u >> 11;

                // Special case for the base segment.
                if (0 == s)
                {
                    if (u2 < __xComp[0])
                    {
                        // Generated x is within R0.
                        return(u2 * __INCR * __A_Div_Y0 * sign);
                    }
                    // Generated x is in the tail of the distribution.
                    return(SampleTail(rng) * sign);
                }

                // All other segments.
                if (u2 < __xComp[s])
                {
                    // Generated x is within the rectangle.
                    return(u2 * __INCR * __x[s] * 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 is relatively rarely executed,
                // although more often than the 'tail' path (above).
                double x = u2 * __INCR * __x[s];
                if (__y[s - 1] + ((__y[s] - __y[s - 1]) * rng.NextDouble()) < GaussianPdfDenorm(x))
                {
                    return(x * sign);
                }
            }
        }