Last active
June 13, 2018 22:51
-
-
Save craigtp/9889530 to your computer and use it in GitHub Desktop.
BetterRandom - A C# class to produce random numbers which inherits from the .NET framework's System.Random class and so can be a drop-in replacement for usages of the standard Random class, but which uses the RNGCryptoServiceProvider to generate better (and cryptographically secure) random numbers.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Security.Cryptography; | |
namespace BetterRandomNumbers | |
{ | |
// BetterRandom.cs | |
// This class implements a random number generator that is based off the Windows "Next Generation" cryptographically secure | |
// random number generator. It inherits from the base Random class, so can be used as a "drop-in" replacement for the | |
// built-in .NET System.Security.Random class, but providing a superior quality of random numbers. | |
public class BetterRandom : Random, IDisposable | |
{ | |
private const int BufferSize = 1024; // must be a multiple of 4 | |
private readonly byte[] _randomBuffer; | |
private int _bufferOffset; | |
private RNGCryptoServiceProvider rng; | |
public BetterRandom() | |
{ | |
_randomBuffer = new byte[BufferSize]; | |
rng = new RNGCryptoServiceProvider(); | |
_bufferOffset = _randomBuffer.Length; | |
} | |
private void FillBuffer() | |
{ | |
rng.GetBytes(_randomBuffer); | |
_bufferOffset = 0; | |
} | |
public override int Next() | |
{ | |
if (_bufferOffset >= _randomBuffer.Length) | |
{ | |
FillBuffer(); | |
} | |
var val = BitConverter.ToInt32(_randomBuffer, _bufferOffset) & 0x7fffffff; | |
_bufferOffset += sizeof(int); | |
return val; | |
} | |
public override int Next(int maxValue) | |
{ | |
return Next() % maxValue; | |
} | |
public override int Next(int minValue, int maxValue) | |
{ | |
if (maxValue < minValue) | |
{ | |
throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than or equal to minValue"); | |
} | |
var range = maxValue - minValue; | |
return minValue + Next(range); | |
} | |
public override double NextDouble() | |
{ | |
var val = Next(); | |
return (double)val / int.MaxValue; | |
} | |
public void GetBytes(byte[] buff) | |
{ | |
rng.GetBytes(buff); | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
} | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (disposing) | |
{ | |
if (rng != null) | |
{ | |
rng.Dispose(); | |
rng = null; | |
} | |
} | |
GC.SuppressFinalize(this); | |
} | |
} | |
} |
Not really, however you're free to use it however you please.
The output of BetterRandom.Next(int maxValue) is biased, and the bias will be large if the range is large.
See https://ericlippert.com/2013/12/16/how-much-bias-is-introduced-by-the-remainder-technique/
The problems is this code:
return Next() % maxValue;
Something like this idea is better (not tested):
while(true)
{
int value = Next());
if (value < int.MaxValue - int.MaxValue % maxValue)
return value % maxValue;
}
I have concerns about NextDouble too, even with this fix.
After all your objective is to produce better random output than the built-in Random class does...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi. Is there a license attached to this code?