BigInteger Random Number Generator
Updated: July-10,2021
using System;
using System.Numerics;
using System.Security.Cryptography;
public struct RandomBigInt
{
private readonly RNGCryptoServiceProvider _crng;
private int _maxByteWidth;
private int _bitWidth;
public RandomBigInt(int bitWidth)
{
MaxValue = BigIntegerHelper.GetMaxValueBitWidth(bitWidth);
MaxValue.BitWidth = bitWidth;
_maxByteWidth = bitWidth >> 3;
OddsOnly = false;
Unsigned = false;
_crng = new RNGCryptoServiceProvider();
_bitWidth = bitWidth;
}
public bool OddsOnly;
public bool Unsigned;
public int BitWidth
{
get => _bitWidth;
set
{
_bitWidth = value;
MaxValue = BigIntegerHelper.GetMaxValueBitWidth(_bitWidth);
MaxValue.BitWidth = _bitWidth;
_maxByteWidth = _bitWidth >> 3;
}
}
public BigDecimal MaxValue;
public bool NextBool()
{
return Sample() < .5;
}
public BigInteger Next()
{
return Internal();
}
public BigInteger Next(BigInteger minValue, BigInteger maxValue)
{
if (minValue > maxValue)
throw new ArgumentException("maxValue must be greater than or equal to minValue");
return ((BigInteger)(Sample() * (maxValue - minValue)) + minValue) & (BigInteger)MaxValue;
}
public BigInteger Next(BigInteger maxValue)
{
if (maxValue < 0)
throw new ArgumentException("maxValue must be greater than zero.");
return (BigInteger)(Sample() * maxValue) & (BigInteger)MaxValue;
}
public unsafe double NextDouble()
{
var buf = new byte[8];
GetBytes(buf);
fixed (byte* ptr = buf)
{
return *(ulong*)ptr * (1.0 / ulong.MaxValue) * ulong.MaxValue;
}
}
public BigRational NextBigRational()
{
return new BigRational(Internal(), Internal());
}
public decimal NextDecimal()
{
return new decimal((int)Next(int.MaxValue), (int)Next(int.MaxValue), (int)Next(int.MaxValue), NextBool(), (byte)Next(255));
}
public BigDecimal NextBigDecimal()
{
return Sample();
}
public byte[] GetNextByteArray(int size)
{
var ba = new byte[size];
_crng.GetBytes(ba);
return ba;
}
public char[] GetNextCharArray(int size)
{
var xbc = new byte[1];
var ca = new char[size];
var ptr = 0;
do
{
_crng.GetBytes(xbc);
var c = xbc[0];
if (c >= 0x20 && c <= 0x7F)
ca[ptr++] = (char)c;
} while (ptr < size);
return ca;
}
public char NextChar()
{
var xbc = new byte[1];
while (true)
{
_crng.GetBytes(xbc);
var c = xbc[0];
if (c >= 0x20 && c <= 0x7F)
return (char)c;
}
}
public bool[] GetNextBoolArrayLimit(int size)
{
var ba = new bool[size];
const uint ll = uint.MaxValue >> 1;
for (var i = 0; i < size; ++i)
ba[i] = Next(0, uint.MaxValue) > ll;
return ba;
}
public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
{
var ba = new byte[size];
for (var i = 0; i < size; ++i)
ba[i] = (byte)Next(minValue, maxValue);
return ba;
}
public string GetRandomString(int Len)
{
return new string(GetNextCharArray(Len));
}
public string GetRandomString(int minLen, int maxLen)
{
return minLen == maxLen ? new string(GetNextCharArray(minLen)) : new string(GetNextCharArray((int)Next((uint)minLen, (uint)maxLen)));
}
private BigDecimal Sample()
{
var i = Internal();
var s = i * (BigDecimal.One / MaxValue);
if (s.IsZero)
throw new Exception($"Sample is zero. Check BigDecimal BitWidth {MaxValue.BitWidth} Equals BitWidth {_bitWidth}");
return s;
}
public void GetBytes(byte[] data)
{
if (data == null)
throw new ArgumentException("The buffer cannot be null.");
_crng.GetBytes(data);
}
private BigInteger Internal()
{
if (Unsigned)
{
var buffer = new byte[_maxByteWidth + 1];
_crng.GetBytes(buffer);
buffer[_maxByteWidth] = 0;
var n = new BigInteger(buffer);
return !OddsOnly ? n : n | 1;
}
else
{
var buffer = new byte[_maxByteWidth];
_crng.GetBytes(buffer);
var n = new BigInteger(buffer);
return !OddsOnly ? n : n | 1;
}
}
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 + 1);
}
public void GetNonZeroBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException("The buffer cannot be null.");
var index = 0;
do
{
var v = (byte)(Sample() * byte.MaxValue + 1);
if (v > 0)
{
buffer[index] = v;
index++;
}
} while (index < buffer.Length);
}
public string[] GetUniqueStringArray(int numberItems, int minLen, int maxLen)
{
var sl = new MSet15<string>();
do
{
sl.Add(GetRandomString(minLen, maxLen));
} while (sl.Count < numberItems);
return sl.ToArray();
}
}