Welcome to Heliosphan

A Fast Random Number Generator for .NET


Here I present a class that can be substituted in place for the the .NET framework's System.Random class to provide some advantages:

  1. Based on a simple and fast XOR-shift pseudo random number generator (RNG) specified in the paper: Marsaglia, George. (2003). Xorshift RNGs ). This particular implementation of XOR-shift has a period of 2^128-1. See the above paper to see how this can be easily extended 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 and which CLR is used (see table below).

  3. Direct replacement for System.Random. This class implements all of the methods that System.Random does plus some additional methods for generating random uints and booleans. The like named methods are functionally equivalent to those in System.Random.

  4. Allows fast re-initialization with a seed, unlike System.Random which accepts a seed at construction time only, which then executes a relatively expensive initialization 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 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).


I created FastRandom in order to achieve greater speed in a prey capture simulation within another project, SharpNEAT. That simulation requires that the RNG be reset with a given seed 1000s of times per second. FastRandom's Reinitialise() methods, therefore, provide a nice performance boost over System.Random in that case. I then discovered that a number of further performance improvements could be made to the Next*() methods. The first version of FastRandom posted on CodeProject used a multiply-with-carry (MWC) algorithm devised by George Marsaglia. Forum posters pointed out that some seeds generated a sequence of the same number, and whilst investigating the solution, I came across another of Marsaglia's algorithms utilizing an XOR-shift technique that was even faster than MWC. The current version of FastRandom therefore implements XOR-shift and should also provide good random sequences for all seed values (including 0).

The Maths

The random number generator (RNG) used generates new numbers using just bitwise XOR and left and right shifts. The method NextUInt provides the simplest example because it returns the generated 32 bit number (uint) without any further manipulation:

 public uint NextUInt() { uint t= (x^(x<<11)); x=y; y=z; z=w; return (w= (w^(w>>19))^(t^(t>>8))); }

The state of the RNG is described by the four uint variables x, y, z and w. w represents most recently generated number, and a history of the last four generated numbers is maintained with the inclusion of the x, y and z variables. New numbers are generated by applying various shifts and XORs to x, which represents the number generated four calls ago. Storing and using the history of the last four numbers in this manner results in an RNG with a longer period, here the period is 2^128-1. The period can be shortened or lengthened by adjusting the amount of history variables stored. For more information on this, see the paper referred to above. All of the other Next*() methods are variations of this technique, taking the 32 bits generated and manipulating them into double, int, bytes, etc.

Reinitialise Methods

The Reinitialise methods allow the caller to reset FastRandom with a single integer seed value and thus generate the same set of random numbers over again. This can sometimes be useful, e.g., in simulations where you might want to recreate the same scenario exactly as before. Note that System.Random provides no such method for re-initializing (re-seeding) the class once it is constructed; the only option is to construct a new instance and pass the seed in to the constructor, which then executes code to build an array of seed data. By allowing re-initialization and avoiding the need to build a seed data array, FastRandom provides a significant performance improvement.

Other Performance Improvements (in comparison to System.Random) Performance Comparison Table

For prior readers of this article please note that this is an updated version of the table that takes into account improvements made to FastRandom.cs made since the article was first posted and also to the .NET runtime engine between .NET 1.1 and .NET 2.0.

Other notes:
The following performance figures were obtained using released, optimized code executing on an Intel Core 2 Duo E660 overclocked to 3.11Ghz. This is a dual core chip, however these performance figures are for a single core only:


System.Random (millions calls/sec)

FastRandom (millions calls/sec)

Speed increase






142.247 2.14x


87.680 2.54x
Next(int,int) <long range> *


30.261 1.87x


185.528 2.12x
NextBytes() 1024 byte array in tests


0.927 8.83x


261.437 n/a


256.081 n/a


312.500 n/a

* - An alternative execution path occurs when the range between the lower and upper limits will not fit within an int. This results in a different performance figure.

Note the last three methods which are extra methods not present on System.Random. NextUint() is provided because uint is the underlying data type behind FastRandom and so is very fast to generate. NextInt() returns an int (Int32) but unlike Next() the range is between 0 and int.MaxValue instead of between 0 and int.MaxValue-1; this subtle difference allows an optimization to be made (elimination of an 'if' statement). NextBool() is implemented by generating 32 bits (uint) and buffering them for future calls, hence the high speed.


System.Random is actually very fast and achieves its speed mostly by only using simple and fast arithmetic operations such as shift and add. However, the whole class is based around a central Sample() method that returns a double between 0.0 and 1.0, and thus there is some unnecessary floating point arithmetic used to generate integer values. FastRandom utilizes a completely different algorithm for generating random numbers that is inherently slightly faster, and in FastRandom we provide a further boost by avoiding floating point arithmetic wherever possible and implementing some further refinements. Finally, FastRandom also allows for fast re-seeding which allows repeat random number sequences to be re-generated very quickly.

December 2004

Update 2017-05-07 - Performance Benchmarks - Redzen v 3.0.2

These performance benchmark results were obtain using BenchmarkDotNet; the software is available at:

Note. the tests with names ending 10M and 100M give total time for 10 million and 100 million calls respectively. E.g. in the table below the Next10M test has a time of 28.7ms, giving an average time per single call of 2.87 microseconds, which is equivalent to approximate 348 million calls per second; or about 4.3x faster than the equivalent method in System.Random.


BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
Processor=Intel Core i7-6700T CPU 2.80GHz (Skylake), ProcessorCount=8
Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC
  [Host]     : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
  DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

                 Method |      Mean |     Error |    StdDev |
----------------------- |----------:|----------:|----------:|
                Next10M |  28.70 ms | 0.0449 ms | 0.0375 ms |
      NextUpperBound10M |  46.75 ms | 0.0751 ms | 0.0627 ms |
 NextLowerUpperBound10M |  50.20 ms | 0.0210 ms | 0.0164 ms |
          NextDouble10M |  29.91 ms | 0.0935 ms | 0.0829 ms |
          NextBytes100M | 116.74 ms | 0.3242 ms | 0.2874 ms |
           NextFloat10M |  32.35 ms | 0.0271 ms | 0.0254 ms |
            NextUInt10M |  26.59 ms | 0.0117 ms | 0.0109 ms |
                NextInt |  26.70 ms | 0.0153 ms | 0.0143 ms |
   NextDoubleNonZero10M |  32.29 ms | 0.0253 ms | 0.0237 ms |
               NextBool |  31.37 ms | 0.0368 ms | 0.0344 ms |
               NextByte |  24.20 ms | 0.0126 ms | 0.0117 ms |


BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
Processor=Intel Core i7-6700T CPU 2.80GHz (Skylake), ProcessorCount=8
Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC
  [Host]     : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
  DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

                 Method |     Mean |     Error |    StdDev |
----------------------- |---------:|----------:|----------:|
                Next10M | 123.4 ms | 0.0534 ms | 0.0473 ms |
      NextUpperBound10M | 142.2 ms | 0.0310 ms | 0.0259 ms |
 NextLowerUpperBound10M | 138.0 ms | 0.1507 ms | 0.1410 ms |
          NextDouble10M | 116.5 ms | 0.0274 ms | 0.0256 ms |
          NextBytes100M | 979.1 ms | 0.5482 ms | 0.5128 ms |  

Copyright 2004 - 2016 Colin Green.
This article is licensed under a Creative Commons Attribution 3.0 License