Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Created March 24, 2020 09:18
Show Gist options
  • Save mjs3339/6641756672ef1905f19465a4176f0004 to your computer and use it in GitHub Desktop.
Save mjs3339/6641756672ef1905f19465a4176f0004 to your computer and use it in GitHub Desktop.
Fixed BigInteger Random Number Generator
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