Created
March 24, 2020 09:18
-
-
Save mjs3339/6641756672ef1905f19465a4176f0004 to your computer and use it in GitHub Desktop.
Fixed BigInteger Random Number Generator
This file contains hidden or 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; | |
public class FixedBigIntegerRandomNumberGenerator : RandomNumberGenerator | |
{ | |
private readonly int _bitWidthHold; | |
private readonly byte[] _buffer; | |
private readonly BigDecimal _dBi; | |
private readonly FixedBigInteger _maxValueHold = new FixedBigInteger(0, 0); | |
private readonly JitterCacheRng _crng; | |
public FixedBigIntegerRandomNumberGenerator(int bitWidth) | |
{ | |
if (bitWidth < 32) | |
bitWidth = 32; | |
var maxValue = GetMaxValue(bitWidth); | |
var vdp = maxValue.GetDecimalPlaces(); | |
if (vdp > BigDecimal.MaxPrecision) | |
BigDecimal.MaxPrecision = vdp; | |
_bitWidthHold = bitWidth; | |
if (_bitWidthHold < 32) | |
_bitWidthHold = 32; | |
_maxValueHold = maxValue; | |
_dBi = BigDecimal.One / (BigDecimal) maxValue; | |
_buffer = new byte[_bitWidthHold >> 3]; | |
_crng = new JitterCacheRng(1000000); | |
} | |
public FixedBigIntegerRandomNumberGenerator(int bitWidth, int cacheSize) | |
{ | |
if (bitWidth < 32) | |
bitWidth = 32; | |
var maxValue = GetMaxValue(bitWidth); | |
var vdp = maxValue.GetDecimalPlaces(); | |
if (vdp > BigDecimal.MaxPrecision) | |
BigDecimal.MaxPrecision = vdp; | |
_bitWidthHold = bitWidth; | |
if (_bitWidthHold < 32) | |
_bitWidthHold = 32; | |
_maxValueHold = maxValue; | |
_dBi = BigDecimal.One / (BigDecimal) maxValue; | |
_buffer = new byte[_bitWidthHold >> 3]; | |
_crng = new JitterCacheRng(cacheSize); | |
} | |
public bool OddsOnly | |
{ | |
get; | |
set; | |
} | |
public bool Unsigned | |
{ | |
get; | |
set; | |
} | |
protected override void Dispose(bool disposing) | |
{ | |
_crng.Dispose(); | |
} | |
private FixedBigInteger GetMaxValue(int bitWidth) | |
{ | |
var r = new FixedBigInteger(0, bitWidth); | |
for (var i = 0; i < r.Data.Length; ++i) | |
r.Data[i] = uint.MaxValue; | |
r.Data[r.Data.Length - 1] = int.MaxValue; | |
return r; | |
} | |
private FixedBigInteger GetMaxValue() | |
{ | |
var r = new FixedBigInteger(0, _bitWidthHold); | |
for (var i = 0; i < r.Data.Length; ++i) | |
r.Data[i] = uint.MaxValue; | |
r.Data[r.Data.Length - 1] = int.MaxValue; | |
return r; | |
} | |
private BigDecimal Sample() | |
{ | |
FixedBigInteger Internal() | |
{ | |
_crng.GetBytes(_buffer); | |
var n = new FixedBigInteger(_buffer, _bitWidthHold); | |
return !OddsOnly ? n : n | 1; | |
} | |
var s = (BigDecimal) Internal() * _dBi; | |
if (s.Sign == -1) | |
s = s * -1; | |
if (s.IsZero) | |
throw new Exception("Sample is zero. SEE: MaxPrecision in BigDecimal.cs. Default value is 308."); | |
return s; | |
} | |
public FixedBigInteger Next(FixedBigInteger minValue, FixedBigInteger maxValue) | |
{ | |
var sa = Sample(); | |
var fi = (BigDecimal) (maxValue - minValue + minValue); | |
var n = new FixedBigInteger(sa * fi, 0); | |
n = !OddsOnly ? n : n | 1; | |
if (Unsigned) | |
return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n; | |
var buffer = new byte[1]; | |
_crng.GetBytes(buffer); | |
if (buffer[0] > 127) | |
return n.Sign < 0 ? n : new FixedBigInteger(-1, n.Data, 0); | |
return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n; | |
} | |
public FixedBigInteger Next(FixedBigInteger maxValue) | |
{ | |
return Next(0, maxValue); | |
} | |
public FixedBigInteger Next() | |
{ | |
return Next(0, _maxValueHold); | |
} | |
public override void GetBytes(byte[] data) | |
{ | |
if (data == null) | |
throw new ArgumentException("The buffer cannot be null."); | |
_crng.GetBytes(data); | |
} | |
public void NextBytes(byte[] buffer) | |
{ | |
if (buffer == null) | |
throw new ArgumentNullException("The buffer cannot be null."); | |
for (var index = 0; index < buffer.Length; ++index) | |
buffer[index] = (byte) (Sample() * byte.MaxValue); | |
} | |
public FixedBigInteger[] Next(FixedBigInteger minValue, FixedBigInteger maxValue, int arraySize) | |
{ | |
var array = new FixedBigInteger[arraySize]; | |
for (var i = 0; i < arraySize; ++i) | |
array[i] = Next(minValue, maxValue); | |
return array; | |
} | |
public char[] GetNextCharArray(int size) | |
{ | |
var ca = new char[size]; | |
var ptr = 0; | |
do | |
{ | |
ca[ptr++] = (char) Next(32, 128); | |
} while (ptr < size); | |
return ca; | |
} | |
public byte[] GetNextByteArray(int size) | |
{ | |
var ba = new byte[size]; | |
_crng.GetBytes(ba); | |
return ba; | |
} | |
public string GetRandomString(int minLen, int maxLen) | |
{ | |
if (minLen == maxLen) | |
return new string(GetNextCharArray(minLen)); | |
return new string(GetNextCharArray((int) Next((uint) minLen, (uint) maxLen))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment