A fast random number generator for .NET Colin Green, January 2005 Note. A forked version of this class exists in Math.Net at time of writing (XorShift class). Key points: 1) Based on a simple and fast xor-shift pseudo random number generator (RNG) specified in: Marsaglia, George. (2003). Xorshift RNGs. http://www.jstatsoft.org/v08/i14/paper This particular implementation of xorshift has a period of 2^128-1. See the above paper to see how this can be easily extened if you need a longer period. At the time of writing I could find no information on the period of System.Random for comparison. 2) Faster than System.Random. Up to 8x faster, depending on which methods are called. 3) Direct replacement for System.Random. This class implements all of the methods that System.Random does plus some additional methods. The like named methods are functionally equivalent. 4) Allows fast re-initialisation with a seed, unlike System.Random which accepts a seed at construction time which then executes a relatively expensive initialisation routine. This provides a vast speed improvement if you need to reset the pseudo-random number sequence many times, e.g. if you want to re-generate the same sequence of random numbers many times. An alternative might be to cache random numbers in an array, but that approach is limited by memory capacity and the fact that you may also want a large number of different sequences cached. Each sequence can be represented by a single seed value (int) when using FastRandom.
コード例 #1
0
        /// <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.");
        }
コード例 #2
0
 public void NextBytes()
 {
     int sampleCount = 10000000;
     XorShiftRandom rng = new XorShiftRandom();
     byte[] sampleArr = new byte[sampleCount];
     rng.NextBytes(sampleArr);
     NextByteInner(sampleArr);
 }
コード例 #3
0
 /// <summary>
 /// Constructs with the provided world parameter arguments.
 /// </summary>
 public PreyCaptureWorld(int gridSize, int preyInitMoves, double preySpeed, double sensorRange, int maxTimesteps)
 {
     _gridSize = gridSize;
     _preyInitMoves = preyInitMoves;
     _preySpeed = preySpeed;
     _sensorRange = sensorRange;
     _maxTimesteps = maxTimesteps;
     _rng = new XorShiftRandom();
 }
コード例 #4
0
        public void NextByte()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();
            byte[] sampleArr = new byte[sampleCount];
            for(int i=0; i<sampleCount; i++){
                sampleArr[i] = rng.NextByte();

            }
            NextByteInner(sampleArr);
        }
コード例 #5
0
        public void NextDouble()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();
            double[] sampleArr = new double[sampleCount];

            for(int i=0; i<sampleCount; i++){
                sampleArr[i] = rng.NextDouble();
            }

            UniformDistributionTest(sampleArr, 0.0, 1.0);
        }
コード例 #6
0
        public void NextBool()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();

            int trueCount = 0, falseCount = 0;
            double maxExpectedCountErr = sampleCount / 25.0;

            for(int i=0; i<sampleCount; i++) {
                if(rng.NextBool()) trueCount++; else falseCount++;
            }

            double countErr = Math.Abs(trueCount - falseCount);
            if(countErr > maxExpectedCountErr) Assert.Fail();
        }
コード例 #7
0
        public void TestWriteZeroBytes()
        {
            byte[] buf = new byte[0];
            MemoryBlockStream ms = new MemoryBlockStream();
            ms.Write(buf, 0, 0);
            Assert.AreEqual(ms.Length, 0);

            XorShiftRandom rng = new XorShiftRandom(1234567);
            byte[] buf2 = new byte[100];
            rng.NextBytes(buf2);
            ms.Write(buf2, 0, buf2.Length);

            if(!Utils.AreEqual(ms.ToArray(), buf2)) Assert.Fail();

            ms.Write(buf, 0, 0);
            Assert.AreEqual(ms.Length, buf2.Length);
        }
コード例 #8
0
        /// <summary>
        /// Genetic mutation for auxiliary argument data.
        /// </summary>
        public void MutateAuxArgs(double[] auxArgs, XorShiftRandom rng, ZigguratGaussianSampler gaussianSampler, double connectionWeightRange)
        {
            // Mutate center.
            // Add gaussian ditribution sample and clamp result to +-connectionWeightRange.
            double tmp = auxArgs[0] + gaussianSampler.NextSample(0, _auxArgsMutationSigmaCenter);
            if(tmp < -connectionWeightRange) {
                auxArgs[0] = -connectionWeightRange;
            }
            else if(tmp > connectionWeightRange) {
                auxArgs[0] = connectionWeightRange;
            }
            else {
                auxArgs[0] = tmp;
            }

            // Mutate radius.
            // Add gaussian ditribution sample and clamp result to [0,1]
            tmp = auxArgs[1] + gaussianSampler.NextSample(0, _auxArgsMutationSigmaRadius);
            if(tmp < 0.0) {
                auxArgs[1] = 0.0;
            }
            else if(tmp > 1.0) {
                auxArgs[1] = 1.0;
            }
            else {
                auxArgs[1] = tmp;
            }
        }
コード例 #9
0
 /// <summary>
 /// For activation functions that accept auxiliary arguments; generates random initial values for aux arguments for newly
 /// added nodes (from an 'add neuron' mutation).
 /// </summary>
 public double[] GetRandomAuxArgs(XorShiftRandom rng, double connectionWeightRange)
 {
     double[] auxArgs = new double[2];
     auxArgs[0] = (rng.NextDouble()-0.5) * 2.0;
     auxArgs[1] = rng.NextDouble();
     return auxArgs;
 }
コード例 #10
0
ファイル: WalkerWorld.cs プロジェクト: colgreen/sharpneat
 /// <summary>
 /// Constructor accepting a trackLength parameter (length of the track that the walker is walking along).
 /// </summary>
 /// <param name="trackLength"></param>
 /// <param name="rng">Random number generator.</param>
 public WalkerWorld(XorShiftRandom rng, float trackLength)
 {
     _rng = rng;
     _trackLength = trackLength;
     _trackLengthHalf = trackLength * 0.5f;
 }
コード例 #11
0
 /// <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);
 }
コード例 #12
0
 /// <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;
 }
コード例 #13
0
ファイル: TestCaseField.cs プロジェクト: colgreen/sharpneat
 /// <summary>
 /// Default constructor.
 /// </summary>
 public TestCaseField()
 {
     _rng = new XorShiftRandom();
 }
コード例 #14
0
 /// <summary>
 /// Randomly select a function based on each function's selection probability.
 /// </summary>
 public ActivationFunctionInfo GetRandomFunction(XorShiftRandom rng)
 {
     return _functionList[DiscreteDistributionUtils.Sample(_rwl, rng)];
 }
コード例 #15
0
ファイル: NumericsUtils.cs プロジェクト: colgreen/Redzen
 /// <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;
 }
コード例 #16
0
ファイル: WalkerWorld.cs プロジェクト: colgreen/sharpneat
 /// <summary>
 /// Default constructor.
 /// </summary>
 public WalkerWorld(XorShiftRandom rng) : this(rng, 300)
 {}
コード例 #17
0
ファイル: NullFn.cs プロジェクト: colgreen/sharpneat
 /// <summary>
 /// For activation functions that accept auxiliary arguments; generates random initial values for aux arguments for newly
 /// added nodes (from an 'add neuron' mutation).
 /// </summary>
 public double[] GetRandomAuxArgs(XorShiftRandom rng, double connectionWeightRange)
 {
     throw new SharpNeatException("GetRandomAuxArgs() called on activation function that does not use auxiliary arguments.");
 }
コード例 #18
0
        public void NextLowerUpper_LongRange_Distribution()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();

            int maxValHalf = int.MaxValue / 2;
            int lowerBound = -(maxValHalf + 10000);
            int upperBound = (maxValHalf + 10000);

            // N.B. double precision can represent every Int32 value exactly.
            double[] sampleArr = new double[sampleCount];
            for(int i=0; i<sampleCount; i++) {
                sampleArr[i] = rng.Next(lowerBound, upperBound);
            }

            UniformDistributionTest(sampleArr, lowerBound, upperBound);
        }
コード例 #19
0
        public void NextLowerUpper_LongRange_Bounds()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();
            Random sysRng = new Random();

            int maxValHalf = int.MaxValue / 2;
            double[] sampleArr = new double[sampleCount];

            for(int i=0; i<sampleCount; i++)
            {
                int lowerBound = -(maxValHalf + (sysRng.Next()/2));
                int upperBound = (maxValHalf + (sysRng.Next()/2));
                int sample = rng.Next(lowerBound, upperBound);

                if(sample < lowerBound || sample >= upperBound) {
                    Assert.Fail();
                }
            }
        }
コード例 #20
0
        public void NextLowerUpper()
        {
            int sampleCount = 10000000;
            XorShiftRandom rng = new XorShiftRandom();
            double[] sampleArr = new double[sampleCount];

            for(int i=0; i<sampleCount; i++){
                sampleArr[i] = rng.Next(1000000, 1234567);
            }

            UniformDistributionTest(sampleArr, 1000000, 1234567);
        }
コード例 #21
0
ファイル: MemoryStreamFuzzer.cs プロジェクト: colgreen/Redzen
 public MemoryStreamFuzzer(MemoryStream strmA, MemoryBlockStream strmB, int seed)
 {
     _strmA = strmA;
     _strmB = strmB;
     _rng = new XorShiftRandom(seed);
 }
コード例 #22
0
ファイル: NullFn.cs プロジェクト: colgreen/sharpneat
 /// <summary>
 /// Genetic mutation for auxiliary argument data.
 /// </summary>
 public void MutateAuxArgs(double[] auxArgs, XorShiftRandom rng, ZigguratGaussianSampler gaussianSampler, double connectionWeightRange)
 {
     throw new SharpNeatException("MutateAuxArgs() called on activation function that does not use auxiliary arguments.");
 }
コード例 #23
0
        /// <summary>
        /// Construct with the provided RNG source.
        /// </summary>
        public ZigguratGaussianSampler(XorShiftRandom rng)
        {
            _rng = rng;

            // Initialise rectangle position data.
            // _x[i] and _y[i] describe the top-right position ox Box i.

            // Allocate storage. We add one to the length of _x so that we have an entry at _x[_blockCount], this avoids having
            // to do a special case test when sampling from the top box.
            _x = new double[__blockCount + 1];
            _y = new double[__blockCount];

            // Determine top right position of the base rectangle/box (the rectangle with the Gaussian tale attached).
            // We call this Box 0 or B0 for short.
            // Note. x[0] also describes the right-hand edge of B1. (See diagram).
            _x[0] = __R;
            _y[0] = GaussianPdfDenorm(__R);

            // The next box (B1) has a right hand X edge the same as B0.
            // Note. B1's height is the box area divided by its width, hence B1 has a smaller height than B0 because
            // B0's total area includes the attached distribution tail.
            _x[1] = __R;
            _y[1] =  _y[0] + (__A / _x[1]);

            // Calc positions of all remaining rectangles.
            for(int i=2; i<__blockCount; i++)
            {
                _x[i] = GaussianPdfDenormInv(_y[i-1]);
                _y[i] = _y[i-1] + (__A / _x[i]);
            }

            // For completeness we define the right-hand edge of a notional box 6 as being zero (a box with no area).
            _x[__blockCount] = 0.0;

            // Useful precomputed values.
            _A_Div_Y0 = __A / _y[0];
            _xComp = new uint[__blockCount];

            // Special case for base box. _xComp[0] stores the area of B0 as a proportion of __R
            // (recalling that all segments have area __A, but that the base segment is the combination of B0 and the distribution tail).
            // Thus -xComp[0[ is the probability that a sample point is within the box part of the segment.
            _xComp[0] = (uint)(((__R * _y[0]) / __A) * (double)uint.MaxValue);

            for(int i=1; i<__blockCount-1; i++) {
                _xComp[i] = (uint)((_x[i+1] / _x[i]) * (double)uint.MaxValue);
            }
            _xComp[__blockCount-1] = 0;  // Shown for completeness.

            // Sanity check. Test that the top edge of the topmost rectangle is at y=1.0.
            // Note. We expect there to be a tiny drift away from 1.0 due to the inexactness of floating
            // point arithmetic.
            Debug.Assert(Math.Abs(1.0 - _y[__blockCount-1]) < 1e-10);
        }