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(); } }