RandomBigInt.cs

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

Leave a Reply

Your email address will not be published. Required fields are marked *