CustomToolTip.cs

Customer ToolTip Class

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
/// <summary>
///     A custom tooltip class which adds some things I would like to see. I originally wrote this to have access to the
///     tooltip text.
/// </summary>
public class CustomToolTip : ToolTip
{
    private readonly float[]    _GradientPositions;
    private readonly ColorBlend gradientBlender;
    private          Color      _gradientEndColor    = Color.DeepSkyBlue;
    private          Color      _gradientMiddleColor = Color.LightSkyBlue;
    private          Color      _gradientStartColor  = Color.LightSkyBlue;
    public CustomToolTip()
    {
        Font                      =  new Font("Arial Narrow", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
        _GradientPositions        =  new float[3];
        _GradientPositions[0]     =  0f;
        _GradientPositions[1]     =  .3f;
        _GradientPositions[2]     =  1f;
        gradientBlender           =  new ColorBlend(3) {Positions = _GradientPositions};
        gradientBlender.Colors[0] =  _gradientStartColor;
        gradientBlender.Colors[1] =  _gradientMiddleColor;
        gradientBlender.Colors[2] =  _gradientEndColor;
        OwnerDraw                 =  true;
        Popup                     += OnPopup;
        Draw                      += OnDraw;
    }
    /// <summary>
    ///     The font used in the drawing of the text.
    /// </summary>
    [Description("The font used in the drawing of the text.")]
    public Font Font
    {
        get;
        set;
    }
    /// <summary>
    ///     The background image used in the control.
    /// </summary>
    [Description("The background image used in the control.")]
    public Image BackgroundImage
    {
        get;
        set;
    }
    /// <summary>
    ///     Sets the color of the border
    /// </summary>
    [Description("Sets the color of the border")]
    public Color BorderColor
    {
        get;
        set;
    } = Color.DodgerBlue;
    /// <summary>
    ///     Enables or disables the drawing of the border
    /// </summary>
    [Description("Enables or disables the drawing of the border")]
    public bool EnableBorder
    {
        get;
        set;
    } = true;
    /// <summary>
    ///     Enables or disables the drawing of the Gradient Background
    /// </summary>
    [Description("Enables or disables the drawing of the Gradient Background")]
    public bool EnableGradientBackground
    {
        get;
        set;
    } = false;
    public string Text
    {
        get;
        set;
    } = "";
    /// <summary>
    ///     Sets the direction of the gradient
    /// </summary>
    [Description("Sets the direction of the gradient")]
    public LinearGradientMode GradientMode
    {
        get;
        set;
    } = LinearGradientMode.Vertical;
    /// <summary>
    ///     Sets the color of the start of the gradient
    /// </summary>
    [Description("Sets the color of the start of the gradient")]
    public Color GradientStartColor
    {
        get => _gradientStartColor;
        set
        {
            _gradientStartColor       = value;
            gradientBlender.Colors[0] = _gradientStartColor;
        }
    }
    /// <summary>
    ///     Sets the color of the middle of the gradient
    /// </summary>
    [Description("Sets the color of the middle of the gradient")]
    public Color GradientMiddleColor
    {
        get => _gradientMiddleColor;
        set
        {
            _gradientMiddleColor      = value;
            gradientBlender.Colors[1] = _gradientMiddleColor;
        }
    }
    /// <summary>
    ///     Sets the color of the end of the gradient
    /// </summary>
    [Description("Sets the color of the end of the gradient")]
    public Color GradientEndColor
    {
        get => _gradientEndColor;
        set
        {
            _gradientEndColor         = value;
            gradientBlender.Colors[2] = _gradientEndColor;
        }
    }
    /// <summary>
    ///     Set or Get the lower,center,upper bounds for the gradient brush
    /// </summary>
    [Category("Behavior")]
    [Description("Set or Get the lower,center,upper bounds for the gradient brush")]
    public float[] GradientPositions
    {
        get => _GradientPositions;
        set
        {
            _GradientPositions[0]     = value[0];
            _GradientPositions[1]     = value[1];
            _GradientPositions[2]     = value[2];
            gradientBlender.Positions = _GradientPositions;
        }
    }
    private void OnPopup(object sender, PopupEventArgs e)
    {
        var tt     = GetToolTip(e.AssociatedControl);
        var newstr = tt.Replace(@"\n", Environment.NewLine);
        e.ToolTipSize = newstr.MeasureText(Font, 1, 1);
    }
    private void OnDraw(object sender, DrawToolTipEventArgs e)
    {
        var fs = Font.GetFontSize();
        var g  = e.Graphics;
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.InterpolationMode  = InterpolationMode.High;
        Text                 = e.ToolTipText;
        var newstr = e.ToolTipText.Replace(@"\n", Environment.NewLine);
        if (BackgroundImage == null)
            if (EnableGradientBackground)
            {
                var b = new LinearGradientBrush(e.Bounds, Color.Black, Color.Black, GradientMode) {InterpolationColors = gradientBlender};
                g.FillRectangle(b, e.Bounds);
            }
            else
            {
                g.FillRectangle(new SolidBrush(BackColor), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
            }
        else
            g.DrawImage(new Bitmap(BackgroundImage, e.Bounds.Width, e.Bounds.Height), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
        g.DrawString(newstr, Font, new SolidBrush(ForeColor), new PointF(e.Bounds.X + fs.Width / 2, e.Bounds.Y + fs.Height / 2));
        if (EnableBorder)
            g.DrawRectangle(new Pen(new SolidBrush(BorderColor), 1), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1));
    }
}

LongLong.cs

Int64 Bit Class

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
///     Used to verify correct mathematical operations before extending to 128, 256, 512, 1024, and 2048 versions
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(LongLongConverter))]
[DebuggerDisplay("{DDisplay}")]
public struct LongLong : IComparable<LongLong>, IComparable, IEquatable<LongLong>, IConvertible, IFormattable
{
    private ulong B64;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public static LongLong Zero     = new LongLong(0);
    public static LongLong Ten      = new LongLong(10);
    public static LongLong One      = new LongLong(1);
    public static LongLong MaxValue = GetMaxValue();
    public static LongLong MinValue = GetMinValue();
    private static LongLong GetMaxValue()
    {
        return new LongLong(ulong.MaxValue);
    }
    private static LongLong GetMinValue()
    {
        return new LongLong(0);
    }
    public LongLong(LongLong value)
    {
        B64 = value.B64;
    }
    public LongLong(string value)
    {
        if (!TryParse(value, out var result))
            throw new Exception("TryParse Failed.");
        B64 = result.B64;
    }
    public LongLong(byte value)
    {
        B64 = value;
    }
    public LongLong(bool value)
    {
        B64 = (ulong) (value ? 1 : 0);
    }
    public LongLong(char value)
    {
        B64 = value;
    }
    public LongLong(decimal value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        var bits = decimal.GetBits(value);
        B64 = (uint) bits[0];
        if (value < 0)
            B64 = ~B64;
    }
    public LongLong(double value) : this((decimal) value)
    {
    }
    public LongLong(float value) : this((decimal) value)
    {
    }
    public LongLong(short value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(int value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(long value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(UInt128 value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = value.B64;
    }
    public LongLong(sbyte value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(ushort value)
    {
        B64 = value;
    }
    public LongLong(uint value)
    {
        B64 = value;
    }
    public LongLong(ulong value)
    {
        B64 = value;
    }
    public LongLong(Guid value) : this(value.ToByteArray())
    {
    }
    public LongLong(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        if (value.Length != 64)
            throw new Exception("Values length must be 64 bytes.");
        B64 = BitConverter.ToUInt64(value, 0);
    }
    //public LongLong(ulong b64)
    //{
    //    B64 = b64;
    //}
    public LongLong(uint[] array)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        var b64 = new byte[8];
        if (array.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(array[0]), 0, b64, 0, 4);
            if (array.Length > 1)
                Array.Copy(BitConverter.GetBytes(array[1]), 0, b64, 4, 4);
        }
        B64 = BitConverter.ToUInt64(b64, 0);
    }
    public int BitWidth
    {
        get
        {
            LongLong bitWidth = 1;
            var      v        = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }
    public override int GetHashCode()
    {
        return B64.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public bool Equals(LongLong obj)
    {
        return B64 == obj.B64;
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int.TryParse(format.Substring(1).Trim(), out var min);
                return ToHexString(ch == 'X', min);
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
    }
    private string ToHexString(bool caps, int min)
    {
        var bytes = ToByteArray().Invert();
        var sb    = new StringBuilder();
        var x     = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info)
    {
        var buf = ToByteArray();
        var bi  = new BigInteger(buf.Concat(new byte[] {0}).ToArray());
        return bi.ToString();
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }
    public ulong ToUInt64(IFormatProvider provider)
    {
        return (ulong) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static LongLong Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static LongLong Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static LongLong Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static LongLong Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }
    public static bool TryParse(string value, out LongLong result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out LongLong result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseHex(value, out result);
        return TryParseNum(value, out result);
    }
    private static bool TryParseHex(string value, out LongLong result)
    {
        if (value.Length > 128)
            throw new OverflowException();
        result = Zero;
        var pos = 0;
        for (var i = value.Length - 1; i >= 0; i--)
        {
            var   ch = value[i];
            ulong bch;
            if (ch >= '0' && ch <= '9')
                bch = (ulong) (ch - '0');
            else if (ch >= 'A' && ch <= 'F')
                bch = (ulong) (ch - 'A' + 10);
            else if (ch >= 'a' && ch <= 'f')
                bch = (ulong) (ch - 'a' + 10);
            else
                return false;
            if (pos < 64)
                result.B64 |= bch << pos;
            pos += 4;
        }
        return true;
    }
    private static bool TryParseNum(string value, out LongLong result)
    {
        result = Zero;
        foreach (var ch in value)
        {
            byte b;
            if (ch >= '0' && ch <= '9')
                b = (byte) (ch - '0');
            else
                return false;
            result =  Ten * result;
            result += b;
        }
        return true;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        return Convert.ToUInt16(B64);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        return Convert.ToUInt32(B64);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        return B64;
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public static int Compare(LongLong left, object right)
    {
        if (right is LongLong)
            return Compare(left, (LongLong) right);
        if (right is bool)
            return Compare(left, new LongLong((bool) right));
        if (right is byte)
            return Compare(left, new LongLong((byte) right));
        if (right is char)
            return Compare(left, new LongLong((char) right));
        if (right is decimal)
            return Compare(left, new LongLong((decimal) right));
        if (right is double)
            return Compare(left, new LongLong((double) right));
        if (right is short)
            return Compare(left, new LongLong((short) right));
        if (right is int)
            return Compare(left, new LongLong((int) right));
        if (right is long)
            return Compare(left, new LongLong((long) right));
        if (right is sbyte)
            return Compare(left, new LongLong((sbyte) right));
        if (right is float)
            return Compare(left, new LongLong((float) right));
        if (right is ushort)
            return Compare(left, new LongLong((ushort) right));
        if (right is uint)
            return Compare(left, new LongLong((uint) right));
        if (right is ulong)
            return Compare(left, new LongLong((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 64)
            return Compare(left, new LongLong(bytes));
        if (right is Guid)
            return Compare(left, new LongLong((Guid) right));
        throw new ArgumentException();
    }
    public static int Compare(LongLong left, LongLong right)
    {
        return left.B64.CompareTo(right.B64);
    }
    public int CompareTo(LongLong value)
    {
        return Compare(this, value);
    }
    public static implicit operator LongLong(bool value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(byte value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(char value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(decimal value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(double value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(short value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(int value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(long value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(sbyte value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(float value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(ushort value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(uint value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(ulong value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(UInt128 value)
    {
        return new LongLong(value);
    }
    public static explicit operator bool(LongLong value)
    {
        return (byte) value.B64 != 0;
    }
    public static explicit operator byte(LongLong value)
    {
        return (byte) value.B64;
    }
    public static explicit operator char(LongLong value)
    {
        return (char) (ushort) value.B64;
    }
    public static explicit operator decimal(LongLong value)
    {
        return new decimal((int) (value.B64 & 0xFFFFFFFF), 0, 0, false, 0);
    }
    public static explicit operator double(LongLong value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(LongLong value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(LongLong value)
    {
        return (short) (int) value.B64;
    }
    public static explicit operator int(LongLong value)
    {
        return (int) value.B64;
    }
    public static explicit operator long(LongLong value)
    {
        return (long) value.B64;
    }
    public static explicit operator uint(LongLong value)
    {
        return (uint) value.B64;
    }
    public static explicit operator ushort(LongLong value)
    {
        return (ushort) value.B64;
    }
    public static explicit operator ulong(LongLong value)
    {
        return value.B64;
    }
    public static explicit operator BigInteger(LongLong value)
    {
        return new BigInteger(value.ToByteArray().Concat(new byte[] {0}).ToArray());
    }
    public static explicit operator UInt128(LongLong value)
    {
        return new UInt128(value.B64);
    }
    public static bool operator >(LongLong left, LongLong right)
    {
        return Compare(left, right) > 0;
    }
    public static bool operator <(LongLong left, LongLong right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(LongLong left, LongLong right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(LongLong left, LongLong right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(LongLong left, LongLong right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(LongLong left, LongLong right)
    {
        return Compare(left, right) == 0;
    }
    public static LongLong operator +(LongLong value)
    {
        return value;
    }
    public static LongLong operator ~(LongLong value)
    {
        return -(value + One);
    }
    public static LongLong operator -(LongLong value)
    {
        return Negate(value);
    }
    public static LongLong operator ++(LongLong value)
    {
        return value + 1;
    }
    public static LongLong operator --(LongLong value)
    {
        return value - 1;
    }
    public static LongLong Negate(LongLong value)
    {
        return new LongLong(~value.B64) + 1;
    }
    public static LongLong operator +(LongLong left, LongLong right)
    {
        left.B64 += right.B64;
        return left;
    }
    public static LongLong operator -(LongLong left, LongLong right)
    {
        return left + -right;
    }
    public static LongLong Add(LongLong left, LongLong right)
    {
        return left + right;
    }
    public static LongLong Subtract(LongLong left, LongLong right)
    {
        return left - right;
    }
    public static LongLong Divide(LongLong dividend, LongLong divisor)
    {
        return DivRem(dividend, divisor, out var integer);
    }
    public static LongLong DivRem(LongLong dividend, LongLong divisor, out LongLong remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quotient, out var rem);
        remainder = new LongLong(rem);
        return new LongLong(quotient);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                ulong di = 0;
                ulong dj;
                var   index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if (dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[0];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len          = GetLength(normalized);
        var unnormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r               = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }
        return unnormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rShift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rShift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static LongLong Remainder(LongLong dividend, LongLong divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }
    public static LongLong Max(LongLong left, LongLong right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }
    public static LongLong Min(LongLong left, LongLong right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }
    public static int GetBitWidth(LongLong n)
    {
        LongLong bitWidth = 1;
        var      v        = n;
        while ((v >>= 1) > 0)
            bitWidth++;
        if (bitWidth < 8)
            bitWidth = 8;
        while (bitWidth % 8 != 0)
            bitWidth++;
        return (int) bitWidth;
    }
    public static LongLong operator %(LongLong dividend, LongLong divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static LongLong operator /(LongLong dividend, LongLong divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        return new[] {B64};
    }
    public ulong[] ToUIn64Array(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 8;
        if (al * 8 != value.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 4;
        if (al * 4 != value.Length)
            al++;
        var arr = new uint[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array(ulong[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var arr = new uint[value.Length * 2];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public ulong[] ToUIn64Array(uint[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 2;
        if (al * 2 != value.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array()
    {
        var uia = new uint[16];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, uia, 0, 64);
        return uia;
    }
    public byte[] ToByteArray()
    {
        var ba  = new byte[64];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, ba, 0, 64);
        return ba;
    }
    public static LongLong Multiply(LongLong left, LongLong right)
    {
        var xInts   = left.ToUIn32Array();
        var yInts   = right.ToUIn32Array();
        var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        return new LongLong(mulInts);
    }
    public static LongLong operator *(LongLong left, LongLong right)
    {
        return Multiply(left, right);
    }
    public static LongLong operator >>(LongLong value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift = shift % (length * valueLength);
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i - shiftOffset;
            if (ishift < 0)
                continue;
            shifted[ishift] |= values[i] >> bshift;
            if (bshift > 0 && i + 1 < length)
                shifted[ishift] |= values[i + 1] << (valueLength - bshift);
        }
        return new LongLong(shifted[0]);
    }
    public static LongLong operator <<(LongLong value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift %= length * valueLength;
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i + shiftOffset;
            if (ishift >= length)
                continue;
            shifted[ishift] |= values[i] << bshift;
            if (bshift > 0 && i - 1 >= 0)
                shifted[ishift] |= values[i - 1] >> (valueLength - bshift);
        }
        return new LongLong(shifted[0]);
    }
    public static LongLong operator |(LongLong left, LongLong right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu | yu;
        }
        return new LongLong(z);
    }
    public static LongLong operator ^(LongLong left, LongLong right)
    {
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu ^ yu;
        }
        return new LongLong(z);
    }
    public static LongLong operator &(LongLong left, LongLong right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu & yu;
        }
        return new LongLong(z);
    }
    private class LongLongConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new LongLong();
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

Int512.cs

Int512 Bit Class

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(Int512Converter))]
[DebuggerDisplay("{DDisplay}")]
public struct Int512 : IComparable<Int512>, IComparable, IEquatable<Int512>, IConvertible, IFormattable
{
    private ulong B512;
    private ulong B448;
    private ulong B384;
    private ulong B320;
    private ulong B256;
    private ulong B192;
    private ulong B128;
    private ulong B64;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public static Int512 Zero     = new Int512(0);
    public static Int512 Ten      = new Int512(10);
    public static Int512 One      = new Int512(1);
    public static Int512 MaxValue = GetMaxValue();
    public static Int512 MinValue = GetMinValue();
    private const ulong  HiNeg    = 0x8000000000000000;
    private static Int512 GetMaxValue()
    {
        return new Int512(long.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue);
    }
    private static Int512 GetMinValue()
    {
        return -GetMaxValue();
    }
    public Int512(Int512 value)
    {
        B512 = value.B512;
        B448 = value.B448;
        B384 = value.B384;
        B320 = value.B320;
        B256 = value.B256;
        B192 = value.B192;
        B128 = value.B128;
        B64  = value.B64;
    }
    public Int512(string value)
    {
        if (!TryParse(value, out var result))
            throw new Exception("TryParse Failed.");
        B512 = result.B512;
        B448 = result.B448;
        B384 = result.B384;
        B320 = result.B320;
        B256 = result.B256;
        B192 = result.B192;
        B128 = result.B128;
        B64  = result.B64;
    }
    public Int512(byte value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = value;
    }
    public Int512(bool value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = (ulong) (value ? 1 : 0);
    }
    public Int512(char value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = value;
    }
    public Int512(BigDecimal value)
    {
        var ba = value.UnscaledValue.ToByteArray();
        B512 = BitConverter.ToUInt64(ba, 56);
        B448 = BitConverter.ToUInt64(ba, 48);
        B384 = BitConverter.ToUInt64(ba, 40);
        B320 = BitConverter.ToUInt64(ba, 32);
        B256 = BitConverter.ToUInt64(ba, 24);
        B192 = BitConverter.ToUInt64(ba, 16);
        B128 = BitConverter.ToUInt64(ba, 8);
        B64  = BitConverter.ToUInt64(ba, 0);
    }
    public Int512(decimal value)
    {
        if (value < 0)
        {
            var n = -new Int512(-value);
            B512 = n.B512;
            B448 = n.B448;
            B384 = n.B384;
            B320 = n.B320;
            B256 = n.B256;
            B192 = n.B192;
            B128 = n.B128;
            B64  = n.B64;
            return;
        }
        var bits = decimal.GetBits(value);
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = (uint) bits[2];
        B128 = (uint) bits[1];
        B64  = (uint) bits[0];
    }
    public Int512(double value) : this((decimal) value)
    {
    }
    public Int512(float value) : this((decimal) value)
    {
    }
    public Int512(short value)
    {
        if (value < 0)
        {
            var n = -new Int512(-(value + 1)) - 1;
            B512 = n.B512;
            B448 = n.B448;
            B384 = n.B384;
            B320 = n.B320;
            B256 = n.B256;
            B192 = n.B192;
            B128 = n.B128;
            B64  = n.B64;
            return;
        }
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = (ulong) value;
    }
    public Int512(int value)
    {
        if (value < 0)
        {
            var n = -new Int512(-(value + 1)) - 1;
            B512 = n.B512;
            B448 = n.B448;
            B384 = n.B384;
            B320 = n.B320;
            B256 = n.B256;
            B192 = n.B192;
            B128 = n.B128;
            B64  = n.B64;
            return;
        }
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = (ulong) value;
    }
    public Int512(long value)
    {
        if (value < 0)
        {
            var n = -new Int512(-(value + 1)) - 1;
            B512 = n.B512;
            B448 = n.B448;
            B384 = n.B384;
            B320 = n.B320;
            B256 = n.B256;
            B192 = n.B192;
            B128 = n.B128;
            B64  = n.B64;
            return;
        }
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = (ulong) value;
    }
    public Int512(sbyte value)
    {
        if (value < 0)
        {
            var n = -new Int512(-(value + 1)) - 1;
            B512 = n.B512;
            B448 = n.B448;
            B384 = n.B384;
            B320 = n.B320;
            B256 = n.B256;
            B192 = n.B192;
            B128 = n.B128;
            B64  = n.B64;
            return;
        }
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = (ulong) value;
    }
    public Int512(ushort value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = value;
    }
    public Int512(uint value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = value;
    }
    public Int512(ulong value)
    {
        B512 = 0;
        B448 = 0;
        B384 = 0;
        B320 = 0;
        B256 = 0;
        B192 = 0;
        B128 = 0;
        B64  = value;
    }
    public Int512(BigInteger value) : this(value.ToByteArray())
    {
        var aba = MaxValue.ToByteArray();
        var bn  = new BigInteger(aba);
    }
    public Int512(Guid value) : this(value.ToByteArray())
    {
    }
    public Int512(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        if (value.Length != 64)
            Array.Resize(ref value, 64);
        B512 = BitConverter.ToUInt64(value, 56);
        B448 = BitConverter.ToUInt64(value, 48);
        B384 = BitConverter.ToUInt64(value, 40);
        B320 = BitConverter.ToUInt64(value, 32);
        B256 = BitConverter.ToUInt64(value, 24);
        B192 = BitConverter.ToUInt64(value, 16);
        B128 = BitConverter.ToUInt64(value, 8);
        B64  = BitConverter.ToUInt64(value, 0);
    }
    public Int512(ulong b512, ulong b448, ulong b384, ulong b320, ulong b256, ulong b192, ulong b128, ulong b64)
    {
        B512 = b512;
        B448 = b448;
        B384 = b384;
        B320 = b320;
        B256 = b256;
        B192 = b192;
        B128 = b128;
        B64  = b64;
    }
    public Int512(int sign, uint[] array)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        var b512 = new byte[8];
        var b448 = new byte[8];
        var b384 = new byte[8];
        var b320 = new byte[8];
        var b256 = new byte[8];
        var b192 = new byte[8];
        var b128 = new byte[8];
        var b64  = new byte[8];
        if (array.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(array[0]), 0, b64, 0, 4);
            if (array.Length > 1)
            {
                Array.Copy(BitConverter.GetBytes(array[1]), 0, b64, 4, 4);
                if (array.Length > 2)
                {
                    Array.Copy(BitConverter.GetBytes(array[2]), 0, b128, 0, 4);
                    if (array.Length > 3)
                    {
                        Array.Copy(BitConverter.GetBytes(array[3]), 0, b128, 4, 4);
                        if (array.Length > 4)
                        {
                            Array.Copy(BitConverter.GetBytes(array[4]), 0, b192, 0, 4);
                            if (array.Length > 5)
                            {
                                Array.Copy(BitConverter.GetBytes(array[5]), 0, b192, 4, 4);
                                if (array.Length > 6)
                                {
                                    Array.Copy(BitConverter.GetBytes(array[6]), 0, b256, 0, 4);
                                    if (array.Length > 7)
                                    {
                                        Array.Copy(BitConverter.GetBytes(array[7]), 0, b256, 4, 4);
                                        if (array.Length > 8)
                                        {
                                            Array.Copy(BitConverter.GetBytes(array[8]), 0, b320, 0, 4);
                                            if (array.Length > 9)
                                            {
                                                Array.Copy(BitConverter.GetBytes(array[9]), 0, b320, 4, 4);
                                                if (array.Length > 10)
                                                {
                                                    Array.Copy(BitConverter.GetBytes(array[10]), 0, b384, 0, 4);
                                                    if (array.Length > 11)
                                                    {
                                                        Array.Copy(BitConverter.GetBytes(array[11]), 0, b384, 4, 4);
                                                        if (array.Length > 12)
                                                        {
                                                            Array.Copy(BitConverter.GetBytes(array[12]), 0, b448, 0, 4);
                                                            if (array.Length > 13)
                                                            {
                                                                Array.Copy(BitConverter.GetBytes(array[13]), 0, b448, 4, 4);
                                                                if (array.Length > 14)
                                                                {
                                                                    Array.Copy(BitConverter.GetBytes(array[14]), 0, b512, 0, 4);
                                                                    if (array.Length > 15)
                                                                        Array.Copy(BitConverter.GetBytes(array[15]), 0, b512, 4, 4);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        B512 = BitConverter.ToUInt64(b512, 0);
        B448 = BitConverter.ToUInt64(b448, 0);
        B384 = BitConverter.ToUInt64(b384, 0);
        B320 = BitConverter.ToUInt64(b320, 0);
        B256 = BitConverter.ToUInt64(b256, 0);
        B192 = BitConverter.ToUInt64(b192, 0);
        B128 = BitConverter.ToUInt64(b128, 0);
        B64  = BitConverter.ToUInt64(b64,  0);
        if (sign < 0)
            B512 |= HiNeg;
        else
            B512 &= ~HiNeg;
    }
    public int BitWidth
    {
        get
        {
            Int512 bitWidth = 1;
            var    v        = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }
    public int Sign
    {
        get
        {
            var allZero = true;
            var ba      = ToUIn32Array();
            for (var i = 0; i < ba.Length; i++)
                if (ba[i] != 0)
                {
                    allZero = false;
                    break;
                }
            if (allZero)
                return 0;
            return (B512 & HiNeg) == 0 ? 1 : -1;
        }
    }
    public bool IsOne      => this     == One;
    public bool IsEven     => this % 2 == 0;
    public bool IsNegative => Sign     < 0;
    public bool IsZero     => B512 == 0 && B448 == 0 && B384 == 0 && B320 == 0 && B256 == 0 && B192 == 0 && B128 == 0 && B64 == 0;
    public override int GetHashCode()
    {
        return B64.GetHashCode() ^ B128.GetHashCode() ^ B192.GetHashCode() ^ B256.GetHashCode() ^ B320.GetHashCode() ^ B384.GetHashCode() ^ B448.GetHashCode() ^ B512.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public bool Equals(Int512 obj)
    {
        return B512 == obj.B512 && B448 == obj.B448 && B384 == obj.B384 && B320 == obj.B320 && B256 == obj.B256 && B192 == obj.B192 && B128 == obj.B128 && B64 == obj.B64;
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int.TryParse(format.Substring(1).Trim(), out var min);
                return ToHexString(ch == 'X', min);
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)), 10);
    }
    private string ToHexString(bool caps, int min)
    {
        var bytes = ToByteArray().Invert();
        var sb    = new StringBuilder();
        var x     = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info, int radix)
    {
        if (radix < 2 || radix > 36)
            throw new ArgumentOutOfRangeException("radix");
        if (Sign == 0)
            return "0";
        var          negative = Sign < 0;
        var          a        = negative ? Abs(this) : this;
        var          biRadix  = new Int512(radix);
        const string charSet  = "0123456789abcdefghijklmnopqrstuvwxyz";
        var          al       = new ArrayList();
        while (a.Sign != 0 && a.B64 != 0)
        {
            Divide(a, biRadix, out var remainder, out var quotient);
            al.Insert(0, charSet[(int) remainder.B64]);
            a = quotient;
        }
        var result = new string((char[]) al.ToArray(typeof(char)));
        if (radix == 10 && negative)
            return "-" + result;
        return result;
    }
    public static Int512 Abs(Int512 value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        if (value.Sign < 0)
            return -value;
        return value;
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static Int512 Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static Int512 Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static Int512 Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static Int512 Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }
    public static bool TryParse(string value, out Int512 result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int512 result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseNum(value, 16, out result);
        return TryParseNum(value, 10, out result);
    }
    public static bool TryParseNum(string digits, int radix, out Int512 result)
    {
        result = new Int512();
        if (digits == null)
            return false;
        var multiplier = new Int512(1);
        digits = digits.ToUpper(CultureInfo.CurrentCulture).Trim();
        var nDigits = digits[0] == '-' ? 1 : 0;
        for (var idx = digits.Length - 1; idx >= nDigits; idx--)
        {
            var d = (int) digits[idx];
            if (d >= '0' && d <= '9')
                d -= '0';
            else if (d >= 'A' && d <= 'Z')
                d = d - 'A' + 10;
            else
                return false;
            if (d >= radix)
                return false;
            result     += multiplier * d;
            multiplier *= radix;
        }
        if (digits[0] == '-')
            result = -result;
        return true;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        if (B128 != 0)
            throw new OverflowException();
        return Convert.ToUInt16(B64);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (B128 != 0)
            throw new OverflowException();
        return Convert.ToUInt32(B64);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (B128 != 0)
            throw new OverflowException();
        return B64;
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public static int Compare(Int512 left, object right)
    {
        if (right is Int512)
            return Compare(left, (Int512) right);
        if (right is bool)
            return Compare(left, new Int512((bool) right));
        if (right is byte)
            return Compare(left, new Int512((byte) right));
        if (right is char)
            return Compare(left, new Int512((char) right));
        if (right is decimal)
            return Compare(left, new Int512((decimal) right));
        if (right is double)
            return Compare(left, new Int512((double) right));
        if (right is short)
            return Compare(left, new Int512((short) right));
        if (right is int)
            return Compare(left, new Int512((int) right));
        if (right is long)
            return Compare(left, new Int512((long) right));
        if (right is sbyte)
            return Compare(left, new Int512((sbyte) right));
        if (right is float)
            return Compare(left, new Int512((float) right));
        if (right is ushort)
            return Compare(left, new Int512((ushort) right));
        if (right is uint)
            return Compare(left, new Int512((uint) right));
        if (right is ulong)
            return Compare(left, new Int512((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 64)
            return Compare(left, new Int512(bytes));
        if (right is Guid)
            return Compare(left, new Int512((Guid) right));
        throw new ArgumentException();
    }
    public static int Compare(Int512 left, Int512 right)
    {
        if (ReferenceEquals(left, right))
            return 0;
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("leftSide");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("rightSide");
        if (left > right) return 1;
        if (left == right) return 0;
        return -1;
    }
    public int CompareTo(Int512 value)
    {
        return Compare(this, value);
    }
    public static implicit operator Int512(bool value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(byte value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(char value)
    {
        return new Int512(value);
    }
    public static explicit operator Int512(decimal value)
    {
        return new Int512(value);
    }
    public static explicit operator Int512(double value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(short value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(int value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(long value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(sbyte value)
    {
        return new Int512(value);
    }
    public static explicit operator Int512(float value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(ushort value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(uint value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(ulong value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(BigInteger value)
    {
        return new Int512(value);
    }
    public static implicit operator Int512(BigDecimal value)
    {
        return new Int512(value);
    }
    public static explicit operator bool(Int512 value)
    {
        return (byte) value.B64 != 0;
    }
    public static explicit operator byte(Int512 value)
    {
        return (byte) value.B64;
    }
    public static explicit operator char(Int512 value)
    {
        return (char) (ushort) value.B64;
    }
    public static explicit operator decimal(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        return new decimal((int) (value.B64 & 0xFFFFFFFF), (int) (value.B64 >> 32), (int) (value.B128 & 0xFFFFFFFF), value.Sign < 0, 0);
    }
    public static explicit operator double(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(Int512 value)
    {
        if (value.B64 > 0x8000)
            throw new OverflowException();
        if (value.B64 == 0x8000 && value.Sign > 0)
            throw new OverflowException();
        return (short) ((int) value.B64 * value.Sign);
    }
    public static explicit operator int(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.B64 > 0x80000000)
            throw new OverflowException();
        if (value.B64 == 0x80000000 && value.Sign > 0)
            throw new OverflowException();
        return (int) value.B64 * value.Sign;
    }
    public static explicit operator long(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.B64 > long.MaxValue)
            throw new OverflowException();
        return (long) value.B64 * value.Sign;
    }
    public static explicit operator uint(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value.B64 > uint.MaxValue)
            throw new OverflowException();
        return (uint) value.B64;
    }
    public static explicit operator ushort(Int512 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value.B64 > ushort.MaxValue)
            throw new OverflowException();
        return (ushort) value.B64;
    }
    public static explicit operator ulong(Int512 value)
    {
        if (value.Sign < 0 || value.B64 != 0)
            throw new OverflowException();
        return value.B64;
    }
    public static explicit operator BigInteger(Int512 value)
    {
        return new BigInteger(value.ToByteArray());
    }
    public static bool operator >(Int512 left, Int512 right)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        if (left.Sign != right.Sign)
            return right.Sign < 0;
        if (left.B64 != right.B64)
            return left.B64 > right.B64;
        if (left.B128 != right.B128)
            return left.B128 > right.B128;
        if (left.B192 != right.B192)
            return left.B192 > right.B192;
        if (left.B256 != right.B256)
            return left.B256 > right.B256;
        if (left.B320 != right.B320)
            return left.B320 > right.B320;
        if (left.B384 != right.B384)
            return left.B384 > right.B384;
        if (left.B448 != right.B448)
            return left.B448 > right.B448;
        if (left.B512 != right.B512)
            return left.B512 > right.B512;
        return false;
    }
    public static bool operator <(Int512 left, Int512 right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(Int512 left, Int512 right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(Int512 left, Int512 right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(Int512 left, Int512 right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(Int512 left, Int512 right)
    {
        if (ReferenceEquals(left, right))
            return true;
        if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
            return false;
        if (left.Sign != right.Sign)
            return false;
        return left.Equals(right);
    }
    public static Int512 operator +(Int512 value)
    {
        return value;
    }
    public static Int512 operator ~(Int512 value)
    {
        return -(value + One);
    }
    public static Int512 operator -(Int512 value)
    {
        return Negate(value);
    }
    public static Int512 operator ++(Int512 value)
    {
        return value + 1;
    }
    public static Int512 operator --(Int512 value)
    {
        return value - 1;
    }
    public static Int512 Negate(Int512 value)
    {
        return new Int512(~value.B512, ~value.B448, ~value.B384, ~value.B320, ~value.B256, ~value.B192, ~value.B128, ~value.B64) + 1;
    }
    public static Int512 operator +(Int512 left, Int512 right)
    {
        var  larr   = left.ToUIn32Array();
        var  rarr   = right.ToUIn32Array();
        var  dl     = larr.Length > rarr.Length ? larr.Length : rarr.Length;
        var  result = new uint[dl];
        long carry  = 0;
        for (var i = 0; i < dl; i++)
        {
            var sum = larr[i] + (long) rarr[i] + carry;
            carry     = sum >> 32;
            result[i] = (uint) (sum & 0xFFFFFFFF);
        }
        if (carry != 0)
        {
            var idx = 0;
            while (idx< result.Length-1)
            {
                if (result[idx] == 0)
                    break;
                idx++;
            }
            result[idx] = (uint) carry;
        }
        return new Int512(left.Sign * right.Sign, result);
    }
    public static Int512 operator -(Int512 left, Int512 right)
    {
        return left + -right;
    }
    public static Int512 Add(Int512 left, Int512 right)
    {
        return left + right;
    }
    public static Int512 Subtract(Int512 left, Int512 right)
    {
        return left - right;
    }
    public static Int512 Divide(Int512 dividend, Int512 divisor)
    {
        return DivRem(dividend, divisor, out var integer);
    }
    public static void Divide(Int512 dividend, Int512 divisor, out Int512 remainder, out Int512 quotient)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quo, out var rem);
        remainder = new Int512(1,                            rem);
        quotient  = new Int512(dividend.Sign * divisor.Sign, quo);
    }
    public static Int512 DivRem(Int512 dividend, Int512 divisor, out Int512 remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quotient, out var rem);
        remainder = new Int512(1, rem);
        return new Int512(dividend.Sign * divisor.Sign, quotient);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                ulong di = 0;
                ulong dj;
                var   index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if ((long)dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[0];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len          = GetLength(normalized);
        var unnormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r               = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }
        return unnormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rShift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rShift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static Int512 Remainder(Int512 dividend, Int512 divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }
    public static Int512 Max(Int512 left, Int512 right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }
    public static Int512 Min(Int512 left, Int512 right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }
    public static int GetBitWidth(Int512 n)
    {
        Int512 bitWidth = 1;
        var    v        = n;
        while ((v >>= 1) > 0)
            bitWidth++;
        if (bitWidth < 8)
            bitWidth = 8;
        while (bitWidth % 8 != 0)
            bitWidth++;
        return (int) bitWidth;
    }
    public static Int512 operator %(Int512 dividend, Int512 divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static Int512 operator /(Int512 dividend, Int512 divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        return new[] {B64, B128, B192, B256, B320, B384, B448, B512};
    }
    public uint[] ToUIn32Array()
    {
        var uia = new uint[16];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, uia, 0, 64);
        return uia;
    }
    public byte[] ToByteArray()
    {
        var ba  = new byte[64];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, ba, 0, 64);
        return ba;
    }
    public static Int512 Multiply(Int512 left, Int512 right)
    {
        var xInts   = left.ToUIn32Array();
        var yInts   = right.ToUIn32Array();
        var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        return new Int512(left.Sign * right.Sign, mulInts);
    }
    public static Int512 operator *(Int512 left, Int512 right)
    {
        return Multiply(left, right);
    }
    public static Int512 operator >>(Int512 value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift = shift % (length * valueLength);
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i - shiftOffset;
            if (ishift < 0)
                continue;
            shifted[ishift] |= values[i] >> bshift;
            if (bshift > 0 && i + 1 < length)
                shifted[ishift] |= values[i + 1] << (valueLength - bshift);
        }
        return new Int512(shifted[7], shifted[6], shifted[5], shifted[4], shifted[3], shifted[2], shifted[1], shifted[0]);
    }
    public static Int512 operator <<(Int512 value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift %= length * valueLength;
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i + shiftOffset;
            if (ishift >= length)
                continue;
            shifted[ishift] |= values[i] << bshift;
            if (bshift > 0 && i - 1 >= 0)
                shifted[ishift] |= values[i - 1] >> (valueLength - bshift);
        }
        return new Int512(shifted[7], shifted[6], shifted[5], shifted[4], shifted[3], shifted[2], shifted[1], shifted[0]);
    }
    public static Int512 operator |(Int512 left, Int512 right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu | yu;
        }
        return new Int512(left.Sign * right.Sign, z);
    }
    public static Int512 operator ^(Int512 left, Int512 right)
    {
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu ^ yu;
        }
        return new Int512(left.Sign * right.Sign, z);
    }
    public static Int512 operator &(Int512 left, Int512 right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu & yu;
        }
        return new Int512(left.Sign * right.Sign, z);
    }
    private class Int512Converter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new Int512();
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

Int256.cs

Int256 Bit Class

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(Int256Converter))]
[DebuggerDisplay("{DDisplay}")]
public struct Int256 : IComparable<Int256>, IComparable, IEquatable<Int256>, IConvertible, IFormattable
{
    public ulong Bytes24To32;
    public ulong Bytes16To24;
    public ulong Bytes8To16;
    public ulong Bytes0To8;
    private const ulong HiNeg = 0x8000000000000000;

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();

    public static Int256 Zero = new Int256(0);
    public static Int256 Ten = new Int256(10);
    public static Int256 One = new Int256(1);
    public static Int256 MaxValue = GetMaxValue();
    public static Int256 MinValue = GetMinValue();

    private static Int256 GetMaxValue()
    {
        return new Int256(long.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue);
    }

    private static Int256 GetMinValue()
    {
        return -GetMaxValue();
    }
    public Int256(string value)
    {
        TryParse(value, out var result);
        Bytes24To32 = result.Bytes24To32;
        Bytes16To24 = result.Bytes16To24;
        Bytes8To16 = result.Bytes8To16;
        Bytes0To8 = result.Bytes0To8;
    }
    public Int256(byte value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = value;
    }

    public Int256(bool value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = (ulong) (value ? 1 : 0);
    }

    public Int256(char value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = value;
    }

    public Int256(decimal value)
    {
        if (value < 0)
        {
            var n = -new Int256(-value);
            Bytes24To32 = n.Bytes24To32;
            Bytes16To24 = n.Bytes16To24;
            Bytes8To16 = n.Bytes8To16;
            Bytes0To8 = n.Bytes0To8;
            return;
        }

        var bits = decimal.GetBits(value);
        Bytes24To32 = 0;
        Bytes16To24 = (uint) bits[2];
        Bytes8To16 = (uint) bits[1];
        Bytes0To8 = (uint) bits[0];
        if (value < 0)
        {
            Bytes24To32 = ~Bytes24To32;
            Bytes16To24 = ~Bytes16To24;
            Bytes8To16 = ~Bytes8To16;
            Bytes0To8 = ~Bytes0To8;
        }
    }

    public Int256(double value)
        : this((decimal) value)
    {
    }

    public Int256(float value)
        : this((decimal) value)
    {
    }

    public Int256(short value)
    {
        if (value < 0)
        {
            var n = -new Int256(-(value + 1)) - 1;
            Bytes24To32 = n.Bytes24To32;
            Bytes16To24 = n.Bytes16To24;
            Bytes8To16 = n.Bytes8To16;
            Bytes0To8 = n.Bytes0To8;
            return;
        }

        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = (ulong) value;
    }

    public Int256(int value)
    {
        if (value < 0)
        {
            var n = -new Int256(-(value + 1)) - 1;
            Bytes24To32 = n.Bytes24To32;
            Bytes16To24 = n.Bytes16To24;
            Bytes8To16 = n.Bytes8To16;
            Bytes0To8 = n.Bytes0To8;
            return;
        }

        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = (ulong) value;
    }

    public Int256(long value)
    {
        if (value < 0)
        {
            var n = -new Int256(-(value + 1)) - 1;
            Bytes24To32 = n.Bytes24To32;
            Bytes16To24 = n.Bytes16To24;
            Bytes8To16 = n.Bytes8To16;
            Bytes0To8 = n.Bytes0To8;
            return;
        }

        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = (ulong) value;
    }

    public Int256(sbyte value)
    {
        if (value < 0)
        {
            var n = -new Int256(-(value + 1)) - 1;
            Bytes24To32 = n.Bytes24To32;
            Bytes16To24 = n.Bytes16To24;
            Bytes8To16 = n.Bytes8To16;
            Bytes0To8 = n.Bytes0To8;
            return;
        }

        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = (ulong) value;
    }

    public Int256(ushort value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = value;
    }

    public Int256(uint value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = value;
    }

    public Int256(ulong value)
    {
        Bytes24To32 = 0;
        Bytes16To24 = 0;
        Bytes8To16 = 0;
        Bytes0To8 = value;
    }

    public Int256(Guid value)
        : this(value.ToByteArray())
    {
    }

    public Int256(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        if (value.Length != 32)
            throw new Exception("Values length must be 32 bytes.");
        Bytes24To32 = BitConverter.ToUInt64(value, 24);
        Bytes16To24 = BitConverter.ToUInt64(value, 16);
        Bytes8To16 = BitConverter.ToUInt64(value, 8);
        Bytes0To8 = BitConverter.ToUInt64(value, 0);
    }

    public Int256(ulong msbh, ulong msbl, ulong lsbh, ulong lsbl)
    {
        Bytes24To32 = msbh;
        Bytes16To24 = msbl;
        Bytes8To16 = lsbh;
        Bytes0To8 = lsbl;
    }

    public Int256(int sign, uint[] array)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        var msbh = new byte[8];
        var msbl = new byte[8];
        var lsbh = new byte[8];
        var lsbl = new byte[8];
        if (array.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(array[0]), 0, lsbl, 0, 4);
            if (array.Length > 1)
            {
                Array.Copy(BitConverter.GetBytes(array[1]), 0, lsbl, 4, 4);
                if (array.Length > 2)
                {
                    Array.Copy(BitConverter.GetBytes(array[2]), 0, lsbh, 0, 4);
                    if (array.Length > 3)
                    {
                        Array.Copy(BitConverter.GetBytes(array[3]), 0, lsbh, 4, 4);
                        if (array.Length > 4)
                        {
                            Array.Copy(BitConverter.GetBytes(array[4]), 0, msbl, 0, 4);
                            if (array.Length > 5)
                            {
                                Array.Copy(BitConverter.GetBytes(array[5]), 0, msbl, 4, 4);
                                if (array.Length > 6)
                                {
                                    Array.Copy(BitConverter.GetBytes(array[6]), 0, msbh, 0, 4);
                                    if (array.Length > 7)
                                        Array.Copy(BitConverter.GetBytes(array[7]), 0, msbh, 4, 4);
                                }
                            }
                        }
                    }
                }
            }
        }

        Bytes24To32 = BitConverter.ToUInt64(msbh, 0);
        Bytes16To24 = BitConverter.ToUInt64(msbl, 0);
        Bytes8To16 = BitConverter.ToUInt64(lsbh, 0);
        Bytes0To8 = BitConverter.ToUInt64(lsbl, 0);
        if (sign < 0)
            Bytes24To32 |= HiNeg;
        else
            Bytes24To32 &= ~HiNeg;
    }

    public ulong MSBH => Bytes24To32;
    public ulong MSBL => Bytes16To24;
    public ulong LSBH => Bytes8To16;
    public ulong LSBL => Bytes0To8;

    public int BitWidth
    {
        get
        {
            Int256 bitWidth = 1;
            var v = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }

    public int Sign
    {
        get
        {
            if (Bytes24To32 == 0 && Bytes16To24 == 0 && Bytes8To16 == 0 && Bytes0To8 == 0)
                return 0;
            return (Bytes24To32 & HiNeg) == 0 ? 1 : -1;
        }
    }

    public override int GetHashCode()
    {
        return MSBH.GetHashCode() ^ MSBL.GetHashCode() ^ LSBH.GetHashCode() ^ LSBL.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public bool Equals(Int256 obj)
    {
        return Bytes24To32 == obj.Bytes24To32 && Bytes16To24 == obj.Bytes16To24 && Bytes8To16 == obj.Bytes8To16 &&
               Bytes0To8 == obj.Bytes0To8;
    }

    public override string ToString()
    {
        return ToString(null, null);
    }

    public string ToString(string format)
    {
        return ToString(format, null);
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int.TryParse(format.Substring(1).Trim(), out var min);
                return ToHexString(ch == 'X', min);
            }

            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }

        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
    }

    private string ToHexString(bool caps, int min)
    {
        var bytes = ToByteArray().Invert();
        var sb = new StringBuilder();
        var x = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }

        return sb.ToString();
    }

    private string ToString(NumberFormatInfo info)
    {
        if (Sign == 0)
            return "0";
        var sb = new StringBuilder();
        var current = this;
        current.Bytes24To32 &= ~HiNeg;
        while (true)
        {
            current = DivRem(current, Ten, out var r);
            if (r.Bytes0To8 > 0 || current.Sign != 0 || sb.Length == 0)
                sb.Insert(0, (char) ('0' + r.Bytes0To8));
            if (current.Sign == 0)
                break;
        }

        var s = sb.ToString();
        if (Sign < 0 && s != "0")
            return info.NegativeSign + s;
        return s;
    }

    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }

    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }

    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }

    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }

    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }

    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }

    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }

    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }

    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }

    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }

    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }

    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }

    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }

    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }

        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }

        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }

        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }

        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }

        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }

        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }

        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }

        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }

        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }

        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }

        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }

        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }

        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }

        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }

        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }

        value = null;
        return false;
    }

    public static Int256 Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }

    public static Int256 Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }

    public static Int256 Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }

    public static Int256 Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }

    public static bool TryParse(string value, out Int256 result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }

    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int256 result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value = value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value = value.Substring(2);
            }
        }

        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseHex(value, out result);
        return TryParseNum(value, out result);
    }

    private static bool TryParseHex(string value, out Int256 result)
    {
        if (value.Length > 64)
            throw new OverflowException();
        result = Zero;
        var pos = 0;
        for (var i = value.Length - 1; i >= 0; i--)
        {
            var ch = value[i];
            ulong bch;
            if (ch >= '0' && ch <= '9')
                bch = (ulong) (ch - '0');
            else if (ch >= 'A' && ch <= 'F')
                bch = (ulong) (ch - 'A' + 10);
            else if (ch >= 'a' && ch <= 'f')
                bch = (ulong) (ch - 'a' + 10);
            else
                return false;
            if (pos < 64)
                result.Bytes0To8 |= bch << pos;
            else if (pos < 128)
                result.Bytes8To16 |= bch << pos;
            else if (pos < 192)
                result.Bytes16To24 |= bch << pos;
            else if (pos < 256)
                result.Bytes24To32 |= bch << pos;
            pos += 4;
        }

        return true;
    }

    private static bool TryParseNum(string value, out Int256 result)
    {
        result = Zero;
        foreach (var ch in value)
        {
            byte b;
            if (ch >= '0' && ch <= '9')
                b = (byte) (ch - '0');
            else
                return false;
            result = Ten * result;
            result += b;
        }

        return true;
    }

    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }

    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        if (Bytes8To16 != 0)
            throw new OverflowException();
        return Convert.ToUInt16(Bytes0To8);
    }

    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (Bytes8To16 != 0)
            throw new OverflowException();
        return Convert.ToUInt32(Bytes0To8);
    }

    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (Bytes8To16 != 0)
            throw new OverflowException();
        return Bytes0To8;
    }

    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }

    public static int Compare(Int256 left, object right)
    {
        if (right is Int256)
            return Compare(left, (Int256) right);
        if (right is bool)
            return Compare(left, new Int256((bool) right));
        if (right is byte)
            return Compare(left, new Int256((byte) right));
        if (right is char)
            return Compare(left, new Int256((char) right));
        if (right is decimal)
            return Compare(left, new Int256((decimal) right));
        if (right is double)
            return Compare(left, new Int256((double) right));
        if (right is short)
            return Compare(left, new Int256((short) right));
        if (right is int)
            return Compare(left, new Int256((int) right));
        if (right is long)
            return Compare(left, new Int256((long) right));
        if (right is sbyte)
            return Compare(left, new Int256((sbyte) right));
        if (right is float)
            return Compare(left, new Int256((float) right));
        if (right is ushort)
            return Compare(left, new Int256((ushort) right));
        if (right is uint)
            return Compare(left, new Int256((uint) right));
        if (right is ulong)
            return Compare(left, new Int256((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 32)
            return Compare(left, new Int256(bytes));
        if (right is Guid)
            return Compare(left, new Int256((Guid) right));
        throw new ArgumentException();
    }

    public static int Compare(Int256 left, Int256 right)
    {
        var leftSign = left.Sign;
        var rightSign = right.Sign;
        if (leftSign == 0 && rightSign == 0)
            return 0;
        if (leftSign >= 0 && rightSign < 0)
            return 1;
        if (leftSign < 0 && rightSign >= 0)
            return -1;
        if (left.Bytes24To32 != right.Bytes24To32)
            return left.Bytes24To32.CompareTo(right.Bytes24To32);
        if (left.Bytes16To24 != right.Bytes16To24)
            return left.Bytes16To24.CompareTo(right.Bytes16To24);
        if (left.Bytes8To16 != right.Bytes8To16)
            return left.Bytes8To16.CompareTo(right.Bytes8To16);
        return left.Bytes0To8.CompareTo(right.Bytes0To8);
    }

    public int CompareTo(Int256 value)
    {
        return Compare(this, value);
    }

    public static implicit operator Int256(bool value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(byte value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(char value)
    {
        return new Int256(value);
    }

    public static explicit operator Int256(decimal value)
    {
        return new Int256(value);
    }

    public static explicit operator Int256(double value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(short value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(int value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(long value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(sbyte value)
    {
        return new Int256(value);
    }

    public static explicit operator Int256(float value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(ushort value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(uint value)
    {
        return new Int256(value);
    }

    public static implicit operator Int256(ulong value)
    {
        return new Int256(value);
    }

    public static explicit operator bool(Int256 value)
    {
        return value.Sign != 0;
    }

    public static explicit operator byte(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value.Bytes0To8 > 0xFF)
            throw new OverflowException();
        return (byte) value.Bytes0To8;
    }

    public static explicit operator char(Int256 value)
    {
        if (value.Sign == 0)
            return (char) 0;
        if (value.Sign < 0 || value.Bytes0To8 > 0xFFFF)
            throw new OverflowException();
        return (char) (ushort) value.Bytes0To8;
    }

    public static explicit operator decimal(Int256 value)
    {
        return value.Sign == 0
            ? 0
            : new decimal((int) (value.Bytes0To8 & 0xFFFFFFFF), (int) (value.Bytes8To16 & 0xFFFFFFFF),
                (int) (value.Bytes16To24 & 0xFFFFFFFF), value.Sign < 0, 0);
    }

    public static explicit operator double(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }

    public static explicit operator float(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }

    public static explicit operator short(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Bytes0To8 > 0x8000)
            throw new OverflowException();
        if (value.Bytes0To8 == 0x8000 && value.Sign > 0)
            throw new OverflowException();
        return (short) ((int) value.Bytes0To8 * value.Sign);
    }

    public static explicit operator int(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Bytes0To8 > 0x80000000)
            throw new OverflowException();
        if (value.Bytes0To8 == 0x80000000 && value.Sign > 0)
            throw new OverflowException();
        return (int) value.Bytes0To8 * value.Sign;
    }

    public static explicit operator long(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Bytes0To8 > long.MaxValue)
            throw new OverflowException();
        return (long) value.Bytes0To8 * value.Sign;
    }

    public static explicit operator uint(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value.Bytes0To8 > uint.MaxValue)
            throw new OverflowException();
        return (uint) value.Bytes0To8;
    }

    public static explicit operator ushort(Int256 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value.Bytes0To8 > ushort.MaxValue)
            throw new OverflowException();
        return (ushort) value.Bytes0To8;
    }

    public static explicit operator ulong(Int256 value)
    {
        if (value.Sign < 0 || value.Bytes8To16 != 0)
            throw new OverflowException();
        return value.Bytes0To8;
    }

    public static bool operator >(Int256 left, Int256 right)
    {
        return Compare(left, right) > 0;
    }

    public static bool operator <(Int256 left, Int256 right)
    {
        return Compare(left, right) < 0;
    }

    public static bool operator >=(Int256 left, Int256 right)
    {
        return Compare(left, right) >= 0;
    }

    public static bool operator <=(Int256 left, Int256 right)
    {
        return Compare(left, right) <= 0;
    }

    public static bool operator !=(Int256 left, Int256 right)
    {
        return Compare(left, right) != 0;
    }

    public static bool operator ==(Int256 left, Int256 right)
    {
        return Compare(left, right) == 0;
    }

    public static Int256 operator +(Int256 value)
    {
        return value;
    }
    public static Int256 operator ~(Int256 value)
    {
        return -(value + One);
    }
    public static Int256 operator -(Int256 value)
    {
        return Negate(value);
    }

    public static Int256 operator ++(Int256 value)
    {
        return value + 1;
    }

    public static Int256 operator --(Int256 value)
    {
        return value - 1;
    }

    public static Int256 Negate(Int256 value)
    {
        return new Int256(~value.Bytes24To32, ~value.Bytes16To24, ~value.Bytes8To16, ~value.Bytes0To8) + 1;
    }

    public Int256 ToAbs()
    {
        return Abs(this);
    }

    public static Int256 Abs(Int256 value)
    {
        if (value.Sign < 0)
            return -value;
        return value;
    }

    public static Int256 operator +(Int256 left, Int256 right)
    {
        left.Bytes24To32 += right.Bytes24To32;
        left.Bytes16To24 += right.Bytes16To24;
        if (left.Bytes16To24 < right.Bytes16To24)
            left.Bytes24To32++;
        left.Bytes8To16 += right.Bytes8To16;
        if (left.Bytes8To16 < right.Bytes8To16)
        {
            left.Bytes16To24++;
            if (left.Bytes16To24 < left.Bytes16To24 - 1)
                left.Bytes24To32++;
        }

        left.Bytes0To8 += right.Bytes0To8;
        if (left.Bytes0To8 < right.Bytes0To8)
        {
            left.Bytes8To16++;
            if (left.Bytes8To16 < left.Bytes8To16 - 1)
            {
                left.Bytes16To24++;
                if (left.Bytes16To24 < left.Bytes16To24 - 1)
                    left.Bytes24To32++;
            }
        }

        return left;
    }

    public static Int256 operator -(Int256 left, Int256 right)
    {
        return left + -right;
    }

    public static Int256 Add(Int256 left, Int256 right)
    {
        return left + right;
    }

    public static Int256 Subtract(Int256 left, Int256 right)
    {
        return left - right;
    }

    public static Int256 Divide(Int256 dividend, Int256 divisor)
    {
        return DivRem(dividend, divisor, out var integer);
    }

    public static Int256 DivRem(Int256 dividend, Int256 divisor, out Int256 remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quotient, out var rem);
        remainder = new Int256(1, rem);
        return new Int256(dividend.Sign * divisor.Sign, quotient);
    }

    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit = 0x100000000;
        var divisorLen = GetLength(divisor);
        var dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var div = divisor[0];
            quotient = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem -= q * div;
                quotient[i] = (uint) q;
            }

            remainder[0] = (uint) rem;
            return;
        }

        if (dividendLen >= divisorLen)
        {
            var shift = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor, divisorLen, normDivisor, shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);

                long di = 0;
                long dj;
                var index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj = dqj >> 32;
                    dj = dj >> 32;
                    di = (long) dqj - dj;
                    index++;
                }

                dj = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j] = (uint) qj;
                if (dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum = sum >> 32;
                    }

                    sum += normDividend[j + divisorLen];
                    normDividend[j + divisorLen] = (uint) sum;
                }
            }

            remainder = Unnormalize(normDividend, shift);
            return;
        }

        quotient = new uint[0];
        remainder = dividend;
    }

    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }

    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui = ui << 16;
            shift += 16;
        }

        if ((ui & 0xff000000) == 0)
        {
            ui = ui << 8;
            shift += 8;
        }

        if ((ui & 0xf0000000) == 0)
        {
            ui = ui << 4;
            shift += 4;
        }

        if ((ui & 0xc0000000) == 0)
        {
            ui = ui << 2;
            shift += 2;
        }

        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }

    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len = GetLength(normalized);
        var unnormalized = new uint[len];
        if (shift > 0)
        {
            var rshift = 32 - shift;
            uint r = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }

        return unnormalized;
    }

    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int i;
        uint n = 0;
        if (shift > 0)
        {
            var rShift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n = unormalized[i] >> rShift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }

        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }

    public static Int256 Remainder(Int256 dividend, Int256 divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }

    public static Int256 Max(Int256 left, Int256 right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }

    public static Int256 Min(Int256 left, Int256 right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }

    public static int GetBitWidth(Int256 n)
    {
        Int256 bitWidth = 1;
        var v = n;
        while ((v >>= 1) > 0)
            bitWidth++;
        if (bitWidth < 8)
            bitWidth = 8;
        while (bitWidth % 8 != 0)
            bitWidth++;
        return (int) bitWidth;
    }

    public static Int256 operator %(Int256 dividend, Int256 divisor)
    {
        return Remainder(dividend, divisor);
    }

    public static Int256 operator /(Int256 dividend, Int256 divisor)
    {
        return Divide(dividend, divisor);
    }

    public ulong[] ToUIn64Array()
    {
        return new[] {Bytes0To8, Bytes8To16, Bytes16To24, Bytes24To32};
    }

    public uint[] ToUIn32Array()
    {
        var uia = new uint[8];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, uia, 0, 32);
        return uia;
    }

    public byte[] ToByteArray()
    {
        var ba = new byte[32];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, ba, 0, 32);
        return ba;
    }

    public static Int256 Multiply(Int256 left, Int256 right)
    {
        var xInts = left.ToUIn32Array();
        var yInts = right.ToUIn32Array();
        var mulInts = new uint[16];
        for (var i = 0; i < xInts.Length; i++)
        {
            var index = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder = remainder >> 32;
            }

            while (remainder != 0)
            {
                remainder += mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder = remainder >> 32;
            }
        }

        return new Int256(left.Sign * right.Sign, mulInts);
    }

    public static Int256 operator *(Int256 left, Int256 right)
    {
        return Multiply(left, right);
    }

    public static Int256 operator >>(Int256 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift == int.MinValue)
            return value << int.MaxValue << 1;
        if (shift < 0)
            return value << -shift;
        var digitShift = shift / 32;
        var smallShift = shift - digitShift * 32;
        var xd = value.ToUIn32Array();
        var xl = xd.Length;
        if (value.Sign < 0)
        {
            if (shift >= 32 * xl)
                return new Int256(-1);
            var zd = new uint[xl];
            Array.Copy(xd, zd, xl);
            xd = zd;
            TwosComplement(xd);
        }

        var length = xl - digitShift;
        if (length < 0)
            length = 0;
        var d = new uint[length];
        if (smallShift == 0)
        {
            for (var index = xl - 1; index >= digitShift; --index)
                d[index - digitShift] = xd[index];
        }
        else
        {
            var carryShift = 32 - smallShift;
            uint carry = 0;
            for (var index = xl - 1; index >= digitShift; --index)
            {
                var rot = xd[index];
                d[index - digitShift] = !(value.Sign < 0) || index != xl - 1
                    ? (rot >> smallShift) | carry
                    : (rot >> smallShift) | (uint) (-1 << carryShift);
                carry = rot << carryShift;
            }
        }

        if (value.Sign < 0)
            TwosComplement(d);
        return new Int256(value.Sign, d);
    }

    private static void TwosComplement(uint[] d)
    {
        uint v = 0;
        var i = 0;
        for (; i < d.Length; i++)
        {
            v = ~d[i] + 1;
            d[i] = v;
            if (v != 0)
            {
                i++;
                break;
            }
        }

        if (v != 0)
        {
            for (; i < d.Length; i++)
                d[i] = ~d[i];
        }
        else
        {
            var len = d.Length + 1;
            var r = new uint[len];
            var n = Math.Min(d.Length, len);
            for (var j = 0; j < n; j++)
                r[j] = d[j];
            d = r;
            d[d.Length - 1] = 1;
        }
    }

    public static Int256 operator <<(Int256 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift == int.MinValue)
            return value >> int.MaxValue >> 1;
        if (shift < 0)
            return value >> -shift;
        var digitShift = shift / 32;
        var smallShift = shift - digitShift * 32;
        var xd = value.ToUIn32Array();
        var xl = xd.Length;
        var zd = new uint[xl + digitShift + 1];
        if (smallShift == 0)
        {
            for (var index = 0; index < xl; ++index)
                zd[index + digitShift] = xd[index];
        }
        else
        {
            var carryShift = 32 - smallShift;
            uint carry = 0;
            int index;
            for (index = 0; index < xl; ++index)
            {
                var rot = xd[index];
                zd[index + digitShift] = (rot << smallShift) | carry;
                carry = rot >> carryShift;
            }

            zd[index + digitShift] = carry;
        }

        return new Int256(value.Sign, zd);
    }

    public static Int256 operator |(Int256 left, Int256 right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu | yu;
        }

        return new Int256(left.Sign * right.Sign, z);
    }

    public static Int256 operator ^(Int256 left, Int256 right)
    {
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu ^ yu;
        }

        return new Int256(left.Sign * right.Sign, z);
    }

    public static Int256 operator &(Int256 left, Int256 right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu & yu;
        }

        return new Int256(left.Sign * right.Sign, z);
    }

    public class Int256Converter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new Int256();
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
            Type destinationType)
        {
            return destinationType == typeof(string)
                ? $"{value}"
                : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

MiniSet.cs

A Small Segmented Set Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class MiniSet<T> : IEnumerable
{
    private  Bucket[]             _buckets;
    private  SizeHelper<T>        _newSize = new SizeHelper<T>();
    internal IEqualityComparer<T> Comparer;
    public   int                  Count;
    public   int                  ReSizes;
    public MiniSet(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public MiniSet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer = comparer;
        _buckets = new Bucket[size];
        Count    = 0;
        ReSizes  = 0;
    }
    public int                     ElementCount         => GetElementCount();
    public int                     NumberOfEmptyBuckets => GetNumberOfEmptyBuckets();
    public (int mDepth, int index) MaximumBucketDepth   => GetMaximumBucketDepth();
    public float                   LoadRatio            => GetLoadRatio();
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Clear()
    {
        _buckets.Clear();
    }
    public bool Add(T item)
    {
        EnsureSize();
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        if (FindEntry(item, hashCode).APos != -1)
            return false;
        var pos = hashCode % _buckets.Length;
        if (_buckets[pos] == null)
            _buckets[pos] = new Bucket();
        _buckets[pos].Add(item);
        Count++;
        return true;
    }
    public T[] ToArray()
    {
        var newArray = new T[Count];
        using (var en = GetEnumerator())
        {
            var ptr = 0;
            while (en.MoveNext())
            {
                var value = en.Current;
                if (value == null)
                    break;
                newArray[ptr++] = value;
            }
            return newArray;
        }
    }
    private (int APos, int BPos) FindEntry(T item, int hashCode)
    {
        if (Count == 0)
            return (-1, -1);
        var aPos = hashCode % _buckets.Length;
        var bPos = 0;
        if (_buckets[aPos] == null)
            _buckets[aPos] = new Bucket();
        foreach (var i in _buckets[aPos].Values)
        {
            if (Comparer.Equals(i, item))
                return (aPos, bPos);
            bPos++;
        }
        return (-1, -1);
    }
    private void EnsureSize()
    {
        if (Count >= _buckets.Length)
        {
            ReSizes++;
            var cArray = ToArray();
            _buckets = new Bucket[_newSize.GetNewSize(_buckets.Length)];
            foreach (var i in cArray)
            {
                var hashCode = Comparer.GetHashCode(i) & int.MaxValue;
                var pos      = hashCode % _buckets.Length;
                if (_buckets[pos] == null)
                    _buckets[pos] = new Bucket();
                _buckets[pos].Add(i);
            }
        }
    }
    public bool Contains(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        return FindEntry(item, hashCode).APos != -1;
    }
    public IEnumerator<T> GetEnumerator()
    {
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
                for (var j = 0; j < _buckets[i].Count; ++j)
                    yield return _buckets[i].Values[j];
    }
    public int GetElementCount()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var c = _buckets[i].Count;
                count += c;
            }
        return count;
    }
    public int GetNumberOfEmptyBuckets()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] == null)
                count++;
        return count;
    }
    public int GetNumberOfFilledBuckets()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
                count++;
        return count;
    }
    public (int mDepth, int index) GetMaximumBucketDepth()
    {
        var max = 0;
        var j   = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var count = _buckets[i].Count;
                if (count > max)
                {
                    max = count;
                    j   = i;
                }
            }
        return (max, j);
    }
    public KeyValuePair<int, int>[] BucketDepthList => GetBucketDepthList();
    public KeyValuePair<int, int>[] GetBucketDepthList()
    {
        var bdic = new Dictionary<int, int>();
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var count = _buckets[i].Count;
                if (!bdic.ContainsKey(count))
                {
                    bdic.Add(count, 0);
                    bdic[count]++;
                }
                else
                {
                    bdic[count]++;
                }
            }
        return bdic.OrderByDescending(x=>x.Value).ToArray();
    }
    public float GetLoadRatio()
    {
        var x = Count;
        var y = _buckets.Length;
        var r = x / (float) y;
        return r;
    }
    internal class Bucket
    {
        public int Count;
        public T[] Values;
        public Bucket()
        {
            Values = new T[2];
            Count  = 0;
        }
        public void Add(T item)
        {
            if (Count >= Values.Length)
            {
                var ta = new T[Values.Length + 1];
                Array.Copy(Values, 0, ta, 0, Count);
                Values = ta;
            }
            Values[Count++] = item;
        }
    }
}

MiniArray.cs

A Small Generic Array Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
[Serializable]
public class MiniArray<T> : IEnumerable<T>
{
    public T[] Array;
    public MiniArray() : this(101)
    {
    }
    public MiniArray(int cap)
    {
        Count = 0;
        Array = new T[cap];
    }
    public int Count
    {
        get;
        private set;
    }
    public T this[int index]
    {
        get
        {
            if (index > Array.Length)
                throw new Exception("Error: Index out of range.");
            return Array[index];
        }
        set
        {
            EnsureSize();
            Array[index] = value;
            Count++;
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return new Enumerator<T>(this);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return new Enumerator<T>(this);
    }
    private void EnsureSize()
    {
        if (Count >= Array.Length)
        {
            var NewLength = Array.Length == 0 ? 1 : Array.Length * 2;
            var newtArray = new T[NewLength];
            System.Array.Copy(Array, 0, newtArray, 0, Array.Length);
            Array = newtArray;
        }
    }
    public void Add(T item)
    {
        EnsureSize();
        Array[Count] = item;
        Count++;
    }
    public T[] ToArray()
    {
        var newtArray = new T[Count];
        System.Array.Copy(Array, 0, newtArray, 0, Count);
        return newtArray;
    }
    public IEnumerable<T> All()
    {
        for (var i = 0; i < Count; ++i)
            yield return Array[i];
    }
    public void Clean()
    {
        var newtArray = new T[Count];
        System.Array.Copy(Array, 0, newtArray, 0, Count);
        Array = newtArray;
    }
    public void Clear()
    {
        System.Array.Clear(Array, 0, Count);
        Count = 0;
    }
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Enumerator<T> : IEnumerator<T>
{
    private readonly MiniArray<T> thing;
    private          int          index;
    internal Enumerator(MiniArray<T> thing)
    {
        this.thing = thing;
        index      = 0;
        Current    = default;
    }
    public void Dispose()
    {
    }
    public bool MoveNext()
    {
        var tthing = thing;
        if (index < tthing.Count)
        {
            Current = tthing[index];
            index++;
            return true;
        }
        index   = thing.Count + 1;
        Current = default;
        return false;
    }
    public T Current
    {
        get;
        private set;
    }
    object IEnumerator.Current => Current;
    void IEnumerator.Reset()
    {
        index   = 0;
        Current = default;
    }
}

Int128.cs

Int128 Bit Class

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeConverter(typeof(Int128Converter))]
[DebuggerDisplay("{DDisplay}")]
public struct Int128 : IComparable<Int128>, IComparable, IEquatable<Int128>, IConvertible, IFormattable
{
    public        ulong _hi;
    public        ulong _lo;
    private const ulong HiNeg = 0x8000000000000000;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => "0x" + ToString("X1");
    public static Int128 Zero;
    public static Int128 Ten      = new Int128(10);
    public static Int128 One      = new Int128(1);
    public static Int128 MaxValue = GetMaxValue();
    public static Int128 MinValue = GetMinValue();
    private static Int128 GetMaxValue()
    {
        return new Int128(long.MaxValue, ulong.MaxValue);
    }
    private static Int128 GetMinValue()
    {
        return new Int128(0x8000000000000000, 0);
    }
    /// <summary>
    ///     Either base10 or base 16
    /// </summary>
    public Int128(string value)
    {
        TryParse(value, out var result);
        _hi = result._hi;
        _lo = result._lo;
    }
    public Int128(byte value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(bool value)
    {
        _hi = 0;
        _lo = (ulong) (value ? 1 : 0);
    }
    public Int128(char value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(decimal value)
    {
        if (value < 0)
        {
            var n = -new Int128(-value);
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        var bits = decimal.GetBits(value);
        _hi = (uint) bits[2];
        _lo = (uint) bits[0] | ((ulong) bits[1] << 32);
    }
    public Int128(double value)
        : this((decimal) value)
    {
    }
    public Int128(float value)
        : this((decimal) value)
    {
    }
    public Int128(short value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(int value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(long value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(sbyte value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(ushort value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(uint value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(ulong value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(Guid value)
        : this(value.ToByteArray())
    {
    }
    public Int128(byte[] value)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        if (value.Length != 16)
            throw new ArgumentException(null, "value");
        _hi = BitConverter.ToUInt64(value, 8);
        _lo = BitConverter.ToUInt64(value, 0);
    }
    public Int128(ulong hi, ulong lo)
    {
        _hi = hi;
        _lo = lo;
    }
    public Int128(int sign, uint[] ints)
    {
        if (ints == null)
            throw new ArgumentNullException("ints");
        var lo = new byte[8];
        var hi = new byte[8];
        if (ints.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(ints[0]), 0, lo, 0, 4);
            if (ints.Length > 1)
            {
                Array.Copy(BitConverter.GetBytes(ints[1]), 0, lo, 4, 4);
                if (ints.Length > 2)
                {
                    Array.Copy(BitConverter.GetBytes(ints[2]), 0, hi, 0, 4);
                    if (ints.Length > 3)
                        Array.Copy(BitConverter.GetBytes(ints[3]), 0, hi, 4, 4);
                }
            }
        }
        _lo = BitConverter.ToUInt64(lo, 0);
        _hi = BitConverter.ToUInt64(hi, 0);
        if (sign < 0)
            _hi |= HiNeg;
        else
            _hi &= ~HiNeg;
    }
    public int BitWidth
    {
        get
        {
            Int128 bitWidth = 1;
            var    v        = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }
    public int Sign
    {
        get
        {
            if (_hi == 0 && _lo == 0)
                return 0;
            return (_hi & HiNeg) == 0 ? 1 : -1;
        }
    }
    public override int GetHashCode()
    {
        return _hi.GetHashCode() ^ _lo.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public bool Equals(Int128 obj)
    {
        return _hi == obj._hi && _lo == obj._lo;
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int min;
                int.TryParse(format.Substring(1).Trim(), out min);
                return ToHexString(ch == 'X', min);
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
    }
    private string ToHexString(bool caps, int min)
    {
        var sb = new StringBuilder();
        var x  = caps ? "X" : "x";
        if (min < 0 || min > 16 || _hi != 0)
        {
            sb.Append(min > 16 ? _hi.ToString(x + (min - 16)) : _hi.ToString(x));
            sb.Append(_lo.ToString(x + "16"));
        }
        else
        {
            sb.Append(_lo.ToString(x + min));
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info)
    {
        if (Sign == 0)
            return "0";
        var sb      = new StringBuilder();
        var current = this;
        current._hi &= ~HiNeg;
        Int128 r;
        while (true)
        {
            current = DivRem(current, Ten, out r);
            if (r._lo > 0 || current.Sign != 0 || sb.Length == 0)
                sb.Insert(0, (char) ('0' + r._lo));
            if (current.Sign == 0)
                break;
        }
        var s = sb.ToString();
        if (Sign < 0 && s != "0")
            return info.NegativeSign + s;
        return s;
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static Int128 Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static Int128 Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static Int128 Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static Int128 Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        Int128 result;
        if (!TryParse(value, style, provider, out result))
            throw new ArgumentException(null, "value");
        return result;
    }
    public static bool TryParse(string value, out Int128 result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int128 result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseHex(value, out result);
        return TryParseNum(value, out result);
    }
    private static bool TryParseHex(string value, out Int128 result)
    {
        if (value.Length > 32)
            throw new OverflowException();
        result = Zero;
        var hi  = false;
        var pos = 0;
        for (var i = value.Length - 1; i >= 0; i--)
        {
            var   ch = value[i];
            ulong b;
            if (ch >= '0' && ch <= '9')
                b = (ulong) (ch - '0');
            else if (ch >= 'A' && ch <= 'F')
                b = (ulong) (ch - 'A' + 10);
            else if (ch >= 'a' && ch <= 'f')
                b = (ulong) (ch - 'a' + 10);
            else
                return false;
            if (hi)
            {
                result._hi |= b << pos;
                pos        += 4;
            }
            else
            {
                result._lo |= b << pos;
                pos        += 4;
                if (pos == 64)
                {
                    pos = 0;
                    hi  = true;
                }
            }
        }
        return true;
    }
    private static bool TryParseNum(string value, out Int128 result)
    {
        result = Zero;
        foreach (var ch in value)
        {
            byte b;
            if (ch >= '0' && ch <= '9')
                b = (byte) (ch - '0');
            else
                return false;
            result =  Ten * result;
            result += b;
        }
        return true;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return Convert.ToUInt16(_lo);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return Convert.ToUInt32(_lo);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return _lo;
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public static int Compare(Int128 left, object right)
    {
        if (right is Int128)
            return Compare(left, (Int128) right);
        if (right is bool)
            return Compare(left, new Int128((bool) right));
        if (right is byte)
            return Compare(left, new Int128((byte) right));
        if (right is char)
            return Compare(left, new Int128((char) right));
        if (right is decimal)
            return Compare(left, new Int128((decimal) right));
        if (right is double)
            return Compare(left, new Int128((double) right));
        if (right is short)
            return Compare(left, new Int128((short) right));
        if (right is int)
            return Compare(left, new Int128((int) right));
        if (right is long)
            return Compare(left, new Int128((long) right));
        if (right is sbyte)
            return Compare(left, new Int128((sbyte) right));
        if (right is float)
            return Compare(left, new Int128((float) right));
        if (right is ushort)
            return Compare(left, new Int128((ushort) right));
        if (right is uint)
            return Compare(left, new Int128((uint) right));
        if (right is ulong)
            return Compare(left, new Int128((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 16)
            return Compare(left, new Int128(bytes));
        if (right is Guid)
            return Compare(left, new Int128((Guid) right));
        throw new ArgumentException();
    }
    public byte[] ToByteArray()
    {
        var bytes = new byte[16];
        Buffer.BlockCopy(BitConverter.GetBytes(_lo), 0, bytes, 0, 8);
        Buffer.BlockCopy(BitConverter.GetBytes(_hi), 0, bytes, 8, 8);
        return bytes;
    }
    public static int Compare(Int128 left, Int128 right)
    {
        if (left.Sign < 0)
        {
            if (right.Sign >= 0)
                return -1;
            var xhi = left._hi  & ~HiNeg;
            var yhi = right._hi & ~HiNeg;
            if (xhi != yhi)
                return -xhi.CompareTo(yhi);
            return -left._lo.CompareTo(right._lo);
        }
        if (right.Sign < 0)
            return 1;
        if (left._hi != right._hi)
            return left._hi.CompareTo(right._hi);
        return left._lo.CompareTo(right._lo);
    }
    public int CompareTo(Int128 value)
    {
        return Compare(this, value);
    }
    public static implicit operator Int128(bool value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(byte value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(char value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(decimal value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(double value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(short value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(int value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(long value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(sbyte value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(float value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(ushort value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(uint value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(ulong value)
    {
        return new Int128(value);
    }
    public static explicit operator bool(Int128 value)
    {
        return value.Sign != 0;
    }
    public static explicit operator byte(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > 0xFF)
            throw new OverflowException();
        return (byte) value._lo;
    }
    public static explicit operator char(Int128 value)
    {
        if (value.Sign == 0)
            return (char) 0;
        if (value.Sign < 0 || value._lo > 0xFFFF)
            throw new OverflowException();
        return (char) (ushort) value._lo;
    }
    public static explicit operator decimal(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        return new decimal((int) (value._lo & 0xFFFFFFFF), (int) (value._lo >> 32), (int) (value._hi & 0xFFFFFFFF),
            value.Sign < 0, 0);
    }
    public static explicit operator double(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        double d;
        var    nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        float f;
        var   nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > 0x8000)
            throw new OverflowException();
        if (value._lo == 0x8000 && value.Sign > 0)
            throw new OverflowException();
        return (short) ((int) value._lo * value.Sign);
    }
    public static explicit operator int(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > 0x80000000)
            throw new OverflowException();
        if (value._lo == 0x80000000 && value.Sign > 0)
            throw new OverflowException();
        return (int) value._lo * value.Sign;
    }
    public static explicit operator long(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > long.MaxValue)
            throw new OverflowException();
        return (long) value._lo * value.Sign;
    }
    public static explicit operator uint(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > uint.MaxValue)
            throw new OverflowException();
        return (uint) value._lo;
    }
    public static explicit operator ushort(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > ushort.MaxValue)
            throw new OverflowException();
        return (ushort) value._lo;
    }
    public static explicit operator ulong(Int128 value)
    {
        if (value.Sign < 0 || value._hi != 0)
            throw new OverflowException();
        return value._lo;
    }
    public static bool operator >(Int128 left, Int128 right)
    {
        return Compare(left, right) > 0;
    }
    public static bool operator <(Int128 left, Int128 right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(Int128 left, Int128 right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(Int128 left, Int128 right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(Int128 left, Int128 right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(Int128 left, Int128 right)
    {
        return Compare(left, right) == 0;
    }
    public static Int128 operator +(Int128 value)
    {
        return value;
    }
    public static Int128 operator -(Int128 value)
    {
        return Negate(value);
    }
    public static Int128 operator ~(Int128 value)
    {
        return -(value + One);
    }
    public static Int128 operator ++(Int128 value)
    {
        return value + 1;
    }
    public static Int128 operator --(Int128 value)
    {
        return value - 1;
    }
    public static Int128 Negate(Int128 value)
    {
        return new Int128(~value._hi, ~value._lo) + 1;
    }
    public Int128 ToAbs()
    {
        return Abs(this);
    }
    public static Int128 Abs(Int128 value)
    {
        if (value.Sign < 0)
            return -value;
        return value;
    }
    public static Int128 operator +(Int128 left, Int128 right)
    {
        var add = left;
        add._hi += right._hi;
        add._lo += right._lo;
        if (add._lo < left._lo)
            add._hi++;
        return add;
    }
    public static Int128 operator -(Int128 left, Int128 right)
    {
        return left + -right;
    }
    public static Int128 Add(Int128 left, Int128 right)
    {
        return left + right;
    }
    public static Int128 Subtract(Int128 left, Int128 right)
    {
        return left - right;
    }
    public static Int128 Divide(Int128 dividend, Int128 divisor)
    {
        Int128 integer;
        return DivRem(dividend, divisor, out integer);
    }
    public static Int128 DivRem(Int128 dividend, Int128 divisor, out Int128 remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        uint[] quotient;
        uint[] rem;
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out quotient, out rem);
        remainder = new Int128(1, rem);
        return new Int128(dividend.Sign * divisor.Sign, quotient);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                long di = 0;
                long dj;
                var  index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = (long) dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if (dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[0];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len         = GetLength(normalized);
        var unormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unormalized[i] = (normalized[i] >> shift) | r;
                r              = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unormalized[j] = normalized[j];
        }
        return unormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rshift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rshift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static Int128 Remainder(Int128 dividend, Int128 divisor)
    {
        Int128 remainder;
        DivRem(dividend, divisor, out remainder);
        return remainder;
    }
    public static Int128 operator %(Int128 dividend, Int128 divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static Int128 operator /(Int128 dividend, Int128 divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        return new[] {_hi, _lo};
    }
    public uint[] ToUIn32Array()
    {
        var ints = new uint[4];
        var lob  = BitConverter.GetBytes(_lo);
        var hib  = BitConverter.GetBytes(_hi);
        Buffer.BlockCopy(lob, 0, ints, 0,  4);
        Buffer.BlockCopy(lob, 4, ints, 4,  4);
        Buffer.BlockCopy(hib, 0, ints, 8,  4);
        Buffer.BlockCopy(hib, 4, ints, 12, 4);
        return ints;
    }
    public static Int128 Multiply(Int128 left, Int128 right)
    {
        var xInts   = left.ToUIn32Array();
        var yInts   = right.ToUIn32Array();
        var mulInts = new uint[8];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        return new Int128(left.Sign * right.Sign, mulInts);
    }
    public static Int128 operator *(Int128 left, Int128 right)
    {
        return Multiply(left, right);
    }
    public static Int128 operator >>(Int128 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift < 0)
            return value << -shift;
        shift = shift % 128;
        var shifted = new Int128();
        if (shift > 63)
        {
            shifted._lo = value._hi >> (shift - 64);
            shifted._hi = 0;
        }
        else
        {
            shifted._hi = value._hi >> shift;
            shifted._lo = (value._hi << (64 - shift)) | (value._lo >> shift);
        }
        return shifted;
    }
    public static Int128 operator <<(Int128 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift < 0)
            return value >> -shift;
        shift = shift % 128;
        var shifted = new Int128();
        if (shift > 63)
        {
            shifted._hi = value._lo << (shift - 64);
            shifted._lo = 0;
        }
        else
        {
            var ul = value._lo            >> (64 - shift);
            shifted._hi = ul | (value._hi << shift);
            shifted._lo = value._lo << shift;
        }
        return shifted;
    }
    public static Int128 operator |(Int128 left, Int128 right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu | yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public static Int128 operator ^(Int128 left, Int128 right)
    {
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu ^ yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public static Int128 operator &(Int128 left, Int128 right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu & yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public class Int128Converter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;
            return base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
            {
                Int128 i;
                if (TryParse($"{value}", out i))
                    return i;
            }
            return new Int128();
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
            Type                                                destinationType)
        {
            if (destinationType == typeof(string))
                return $"{value}";
            return base.ConvertTo(context, culture, value, destinationType);
        }
        
    }
}

TinyDictionary.cs

A Small Dictionary Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class TinyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    public TinySet<TKey> Keys;
    public int           Resizes;
    public TValue[]      Values;
    public TinyDictionary() : this(101, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size) : this(size, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size, IEqualityComparer<TKey> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys          = new TinySet<TKey>(size);
        Values        = new TValue[size];
        Keys.Comparer = comparer;
    }
    public TinyDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer = null)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys.Comparer = comparer;
        foreach (var kp in collection)
            Add(kp.Key, kp.Value);
    }
    public int Count => Keys.Count;
    public TValue this[TKey key]
    {
        get
        {
            var pos = Keys.FindEntry(key);
            return pos == -1 ? default : Values[pos];
        }
        set => Add(key, value);
    }
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        return new Enumerator(this);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return new Enumerator(this);
    }
    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
    public bool Add(TKey key, TValue value)
    {
        if (!Keys.Insert(key, true))
        {
            if (Values.Length != Keys.Slots.Length)
            {
                var nValues = new TValue[Keys.Slots.Length];
                Array.Copy(Values, nValues, Values.Length);
                Values = nValues;
                Resizes++;
            }
            Values[Keys.Position] = value;
            return false;
        }
        Values[Keys.Position] = value;
        return true;
    }
    public void Remove(TKey key)
    {
        var pos = Keys.FindEntry(key);
        if (pos != -1)
        {
            Values[pos] = default;
            Keys.Remove(key);
        }
    }
    public bool ContainsKey(TKey key)
    {
        return Keys.FindEntry(key) != -1;
    }
    public int FindKeyIndex(TKey key)
    {
        return Keys.FindEntry(key);
    }
    [Serializable]
    public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDictionaryEnumerator
    {
        private readonly TinyDictionary<TKey, TValue> dictionary;
        private          int                          index;
        internal Enumerator(TinyDictionary<TKey, TValue> dictionary)
        {
            this.dictionary = dictionary;
            index           = 0;
            Current         = new KeyValuePair<TKey, TValue>();
        }
        public bool MoveNext()
        {
            if ((uint) index < (uint) dictionary.Keys.Count)
            {
                Current = new KeyValuePair<TKey, TValue>(dictionary.Keys.Slots[index].Value, dictionary.Values[index]);
                index++;
                return true;
            }
            index   = dictionary.Keys.Count + 1;
            Current = new KeyValuePair<TKey, TValue>();
            return false;
        }
        public KeyValuePair<TKey, TValue> Current
        {
            get;
            private set;
        }
        public void Dispose()
        {
        }
        object IEnumerator.Current
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return new KeyValuePair<TKey, TValue>(Current.Key, Current.Value);
            }
        }
        void IEnumerator.Reset()
        {
            index   = 0;
            Current = new KeyValuePair<TKey, TValue>();
        }
        DictionaryEntry IDictionaryEnumerator.Entry
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return new DictionaryEntry(Current.Key, Current.Value);
            }
        }
        object IDictionaryEnumerator.Key
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return Current.Key;
            }
        }
        object IDictionaryEnumerator.Value
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return Current.Value;
            }
        }
    }
}

EntropySource.cs

Using PC Data Creates a Strong Entropy Source

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
public class EntropySource
{
    private const int Sha3BitSize           = 256;
    private const int Sha3BitBufferMoveSize = Sha3BitSize >> 3;
    private const int CpuDataLength         = 256;
    private const int JitterDataSize        = 256;
    [DllImport("kernel32.dll")]
    private static extern int GetTickCount();
    [DllImport("kernel32.dll")]
    internal static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
    [DllImport("kernel32.dll")]
    internal static extern bool QueryPerformanceFrequency(out long lpFrequency);
    public static byte[] GetBuffer(int bufferSize)
    {
        var rhb = new byte[0];
        var rho = new byte[bufferSize];
        var EntropyThread = new Thread(() =>
        {
            var el        = new List<string>();
            var hashBytes = new HashSet<byte[]>(new ArrayComparer());
            var sw        = new Stopwatch();
            sw.Start();
            AddLocalUserData(hashBytes);
            AddProcessInformation(hashBytes, el);
            AddJitterInformation(hashBytes);
            GetWmiInfor("Win32_PerfRawData_PerfOS_Processor",              hashBytes);
            GetWmiInfor("Win32_PerfRawData_PerfOS_System",                 hashBytes);
            GetWmiInfor("Win32_PerfRawData_Counters_ProcessorInformation", hashBytes);
            GetWmiInfor("Win32_PerfRawData_Counters_Synchronization",      hashBytes);
            GetWmiInfor("Win32_PerfRawData_PerfDisk_LogicalDisk",          hashBytes);
            GetWmiInfor("Win32_PerfRawData_PerfDisk_PhysicalDisk",         hashBytes);
            GetWmiInfor("Win32_PerfFormattedData_PerfOS_Cache",            hashBytes);
            GetWmiInfor("Win32_PerfFormattedData_PerfOS_Memory",           hashBytes);
            GetWmiInfor("Win32_PerfFormattedData_PerfOS_Objects",          hashBytes);
            CpuInfo(hashBytes);
            sw.Stop();
            hashBytes.Add(sw.Elapsed.Ticks.GetBytes());
            rhb = HashBytesToArray(hashBytes);
            AddHistogramInforamation(rhb, hashBytes);
            rhb = HashBytesToArray(hashBytes);
            hashBytes.Clear();
            var div = bufferSize / Sha3BitBufferMoveSize;
            if (div * Sha3BitBufferMoveSize < bufferSize)
                div++;
            var segSize = rhb.Length / div;
            var aseg    = new byte[segSize];
            for (var i = 0; i < div; ++i)
            {
                Buffer.BlockCopy(rhb,                                            i * segSize, aseg, 0,                         segSize);
                Buffer.BlockCopy(new SHA3Managed(Sha3BitSize).ComputeHash(aseg), 0,           rho,  i * Sha3BitBufferMoveSize, Sha3BitBufferMoveSize);
            }
        }) {Priority = ThreadPriority.Highest};
        EntropyThread.Start();
        EntropyThread.Join();
        return rho;
    }
    private static void GetWmiInfor(string key, HashSet<byte[]> hashBytes)
    {
        var wmi = new WMIServices();
        wmi.GetProperties(key);
        foreach (var v in wmi.EntriesList)
        foreach (var p in v.Value)
            hashBytes.Add(p.GetBytesObject());
    }
    private static void CpuInfo(HashSet<byte[]> hashBytes)
    {
        var lhashBytes = new HashSet<byte[]>();
        var dump       = CpuTotalPc.CPULoad;
        do
        {
            var l = (byte) CpuTotalPc.CPULoad;
            if (l != 0)
                lhashBytes.Add(new[] {l});
            Thread.Sleep(1);
        } while (lhashBytes.Count < CpuDataLength);
        foreach (var b in lhashBytes)
            hashBytes.Add(b);
    }
    private static void AddHistogramInforamation(byte[] rhb, HashSet<byte[]> hashBytes)
    {
        var FFTArray = Histogram(rhb);
        for (var i = 0; i < FFTArray.Length; ++i)
            hashBytes.Add(FFTArray[i].GetBytes());
    }
    private static void AddJitterInformation(HashSet<byte[]> hashBytes)
    {
        hashBytes.Add(new JitterEx(JitterDataSize).GetBuffer());
    }
    private static void AddProcessInformation(HashSet<byte[]> hashBytes, List<string> el)
    {
        foreach (var p in Process.GetProcesses())
        {
            try
            {
                hashBytes.Add(p.Id.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.Id.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.HandleCount.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.HandleCount.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.NonpagedSystemMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.NonpagedSystemMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.PagedMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PagedMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.PagedSystemMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PagedSystemMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.PeakPagedMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PeakPagedMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.PeakVirtualMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PeakVirtualMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.PeakWorkingSet64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PeakWorkingSet64.GetBytes()");
            }
            try
            {
                hashBytes.Add(p.PrivateMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.PrivateMemorySize64.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.ProcessName.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.ProcessName.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.Threads.Count.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.Threads.Count.GetBytes())");
            }
            try
            {
                hashBytes.Add(p.SessionId.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.SessionId.GetBytes())");
            }
            for (var i = 0; i < p.Threads.Count; i++)
            {
                try
                {
                    hashBytes.Add(p.Threads[i].CurrentPriority.GetBytes());
                }
                catch (Exception ex)
                {
                    el.Add($"{ex.Message} hashBytes.Add(p.Threads[i].CurrentPriority.GetBytes())");
                }
                try
                {
                    hashBytes.Add(p.Threads[i].Id.GetBytes());
                }
                catch (Exception ex)
                {
                    el.Add($"{ex.Message} hashBytes.Add(p.Threads[i].Id.GetBytes())");
                }
                try
                {
                    hashBytes.Add(p.Threads[i].StartAddress.ToString().GetBytes());
                }
                catch (Exception ex)
                {
                    el.Add($"{ex.Message} hashBytes.Add(p.Threads[i].StartAddress.ToString().GetBytes())");
                }
            }
            try
            {
                hashBytes.Add(p.VirtualMemorySize64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.VirtualMemorySize64.GetBytes()))");
            }
            try
            {
                hashBytes.Add(p.WorkingSet64.GetBytes());
            }
            catch (Exception ex)
            {
                el.Add($"{ex.Message} hashBytes.Add(p.WorkingSet64.GetBytes()))");
            }
        }
    }
    private static void AddLocalUserData(HashSet<byte[]> hashBytes)
    {
        hashBytes.Add(Process.GetCurrentProcess().Id.GetBytes());
        hashBytes.Add(Thread.CurrentThread.ManagedThreadId.GetBytes());
        hashBytes.Add(GetTickCount().GetBytes());
        hashBytes.Add(Process.GetProcesses().Length.GetBytes());
        QueryPerformanceFrequency(out var freq);
        hashBytes.Add(freq.GetBytes());
        for (var i = 0; i < 128; i++)
        {
            QueryPerformanceCounter(out var query);
            hashBytes.Add(query.GetBytes());
        }
        hashBytes.Add(DateTime.Now.Ticks.GetBytes());
        hashBytes.Add(Environment.UserName.GetBytes());
        hashBytes.Add(Environment.MachineName.GetBytes());
        hashBytes.Add(Environment.OSVersion.ToString().GetBytes());
        hashBytes.Add(Environment.ProcessorCount.GetBytes());
        hashBytes.Add(Environment.UserDomainName.GetBytes());
        hashBytes.Add(Environment.StackTrace.GetBytes());
        hashBytes.Add(Environment.GetLogicalDrives().GetBytes());
        hashBytes.Add(MemoryInfo.GetValues().GetBytesObjectSerial());
        hashBytes.Add(MemoryInfo.GetSystemPerformanceInformation().GetBytesObjectSerial());
    }
    private static byte[] HashBytesToArray(HashSet<byte[]> hashBytes)
    {
        byte[] rhb;
        var    ptr   = 0;
        var    count = 0;
        var    arr   = hashBytes.ToArray();
        foreach (var hba in arr)
            count += hba.Length;
        hashBytes.Add(count.GetBytes());
        arr   =  hashBytes.ToArray();
        count += arr.Last().Length;
        rhb   =  new byte[count];
        foreach (var hba in arr)
        {
            Buffer.BlockCopy(hba, 0, rhb, ptr, hba.Length);
            ptr += hba.Length;
        }
        return rhb;
    }
    private static int[] Histogram(IEnumerable<byte> ba)
    {
        var map = new int[256];
        foreach (var i in ba)
            map[i]++;
        return map;
    }
}

ByteArraySegment.cs

Segment a byte array to 16, 32, 64 bit Arrays

using System;
using System.Collections.Generic;
using System.Numerics;
public class ByteArraySegment
{
    public IEnumerable<T[]> SegmentEnum<T>(T[] buffer, int size)
    {
        var idx = 0;
        var ptr = buffer.Length;
        while (ptr >= size)
        {
            var array = new T[size];
            Buffer.BlockCopy(buffer, idx, array, 0, size);
            ptr -= size;
            idx += size;
            yield return array;
        }
    }
    public List<byte[]> SegmentList(byte[] buffer, int size)
    {
        var list = new List<byte[]>(buffer.Length >> 2);
        var idx  = 0;
        var ptr  = buffer.Length;
        while (ptr >= size)
        {
            var _result = new byte[size];
            Buffer.BlockCopy(buffer, idx, _result, 0, size);
            list.Add(_result);
            ptr -= size;
            idx += size;
        }
        return list;
    }
    public char[] SegmentChar(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new char[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public short[] Segment16(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new short[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public ushort[] SegmentU16(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new ushort[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public int[] Segment32(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new int[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public float[] SegmentFloat(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new float[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public uint[] SegmentU32(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new uint[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public long[] Segment64(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new long[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public double[] SegmentDouble(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new double[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public ulong[] SegmentU64(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new ulong[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public BigInteger[] SegmentBI(byte[] buffer, int size)
    {
        var idx  = 0;
        var ptr  = buffer.Length;
        var bi   = new BigInteger[buffer.Length / size];
        var ptr1 = 0;
        while (ptr >= size)
        {
            var array = new byte[size];
            Buffer.BlockCopy(buffer, idx, array, 0, size);
            ptr      -= size;
            idx      += size;
            bi[ptr1++] =  new BigInteger(array);
        }
        return bi;
    }
}