Ellipse.cs

Ellipse Control

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Ellipse : Control
{
    private readonly Color[] _surroundcolors        = {Color.FromArgb(0, 135, 206, 250)};
    private          Color   _centerreflectioncolor = Color.FromArgb(180, 135, 206, 250);
    private          Color   _color                 = Color.DodgerBlue;
    private          Color   _lightColor, _darkColor, _darkDarkColor;
    private          bool    _on           = true;
    private          bool    _reflectionon = true;
    public Ellipse()
    {
        SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true);
        Name           = "Ellipse";
        Size           = new Size(10, 10);
        _lightColor    = ControlPaint.Light(Color.DodgerBlue, .4f);
        _darkColor     = ControlPaint.Dark(_lightColor, .2f);
        _darkDarkColor = ControlPaint.DarkDark(_lightColor);
    }
    [DefaultValue(typeof(Color), "30, 144, 255")]
    public Color Color
    {
        get => _color;
        set
        {
            _color         = value;
            _lightColor    = ControlPaint.Light(value, .4f);
            _darkColor     = ControlPaint.Dark(_lightColor, .2f);
            _darkDarkColor = ControlPaint.DarkDark(_lightColor);
            Invalidate();
        }
    }
    [DefaultValue(typeof(Color), "180, 135, 206, 250")]
    public Color ReflectionColor
    {
        get => _centerreflectioncolor;
        set
        {
            _centerreflectioncolor = value;
            Invalidate();
        }
    }
    [DefaultValue(typeof(bool), "true")]
    public bool On
    {
        get => _on;
        set
        {
            _on = value;
            Invalidate();
        }
    }
    [DefaultValue(typeof(bool), "true")]
    public bool ReflectionOn
    {
        get => _reflectionon;
        set
        {
            _reflectionon = value;
            Invalidate();
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        var offScreenBmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
        using (var g = Graphics.FromImage(offScreenBmp))
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            DrawControl(g, On);
            e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0);
        }
    }
    private void DrawControl(Graphics g, bool on)
    {
        var lightColor = on ? _color : Color.FromArgb(180, _darkColor);
        var darkColor  = on ? _darkColor : _darkDarkColor;
        var width      = Width  - (Padding.Left + Padding.Right);
        var height     = Height - (Padding.Top  + Padding.Bottom);
        var diameter   = Math.Min(width, height);
        diameter = Math.Max(diameter - 1, 1);
        var rectangle = new Rectangle(Padding.Left, Padding.Top, diameter, diameter);
        g.FillEllipse(new SolidBrush(darkColor), rectangle);
        var path = new GraphicsPath();
        path.AddEllipse(rectangle);
        var pathBrush = new PathGradientBrush(path)
        {
            CenterColor    = lightColor,
            SurroundColors = new[] {Color.FromArgb(0, lightColor)}
        };
        g.FillEllipse(pathBrush, rectangle);
        if (_reflectionon)
        {
            var offset    = Convert.ToInt32(diameter        * .15F);
            var diameter1 = Convert.ToInt32(rectangle.Width * .8F);
            var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1);
            var path1     = new GraphicsPath();
            path1.AddEllipse(whiteRect);
            var pathBrush1 = new PathGradientBrush(path)
            {
                CenterColor    = _centerreflectioncolor,
                SurroundColors = _surroundcolors
            };
            g.FillEllipse(pathBrush1, whiteRect);
        }
        g.SetClip(ClientRectangle);
        if (On) g.DrawEllipse(new Pen(Color.FromArgb(85, Color.Black), 1F), rectangle);
    }
}

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

Random64csp.cs

64 Bit Random Number Generator Using RNGCryptoServiceProvider

using System;
using System.Security.Cryptography;
[Serializable]
public class Random64csp : RandomNumberGenerator
{
    private byte[] _buffer;
    private RNGCryptoServiceProvider _crng;
    private double _dBi;
    private ulong UpperLimit = ulong.MaxValue;
    public Random64csp()
    {
        SetDataUse = 8;
        _crng = new RNGCryptoServiceProvider();
    }
    
    public Random64csp(int dataSize)
    {
        SetDataUse = dataSize;
        _crng      = new RNGCryptoServiceProvider();
    }
    
    public int SetDataUse
    {
        get => _buffer.Length;
        set
        {
            var v = value;
            if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7)
                throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8");
            switch (v)
            {
                case 1:
                    _dBi = 1.0D / byte.MaxValue;
                    UpperLimit = byte.MaxValue;
                    _buffer = new byte[1];
                    break;
                case 2:
                    _dBi = 1.0D / ushort.MaxValue;
                    UpperLimit = ushort.MaxValue;
                    _buffer = new byte[2];
                    break;
                case 4:
                    _dBi = 1.0D / uint.MaxValue;
                    UpperLimit = uint.MaxValue;
                    _buffer = new byte[4];
                    break;
                case 8:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
                default:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
            }
        }
    }
    /// <summary>
    ///     Will generate only odd values
    /// </summary>
    public bool OddsOnly
    {
        get;
        set;
    }
    private double Sample()
    {
        ulong Internal()
        {
            _crng.GetBytes(_buffer);
            return BufferToLong(_buffer);
        }
        return Internal() * _dBi;
    }
    public ulong Next(ulong minValue, ulong maxValue)
    {
        var sa = Sample();
        var fi = (double)(maxValue - minValue + minValue);
        var n = (ulong)(sa * fi);
        n = !OddsOnly ? n : n | 1;
        if (n < minValue)
            return Next(minValue, maxValue);
        return n;
    }
    public ulong Next(ulong maxValue)
    {
        return Next(0, maxValue);
    }
    public ulong Next()
    {
        return Next(0, UpperLimit);
    }
    public unsafe double NextDouble()
    {
        var buf = new byte[8];
        GetBytes(buf);
        fixed (byte* ptr = buf)
        {
            return *(ulong*)ptr * _dBi * ulong.MaxValue;
        }
    }
    public char[] GetNextCharArray(int size)
    {
        var xbc = new byte[1];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            var c = xbc[0];
            if (c >= 32 && c <= 127)
                ca[ptr++] = (char)c;
        } while (ptr < size);
        return ca;
    }
    public char[] GetNextCharArrayX(int size)
    {
        var xbc = new byte[2];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            ca[ptr++] = Convert.ToChar(xbc.ToShort());
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    /// <summary>
    ///     Next(0,2)==0?false:true; has a distribution error of 1% weighted toward zero.
    ///     The distribution error here is 0.000000046% which is statistically insignificant in this context.
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    public bool[] GetNextBoolArrayLimit(int size)
    {
        var ba = new bool[size];
        const uint ll = uint.MaxValue >> 1;
        for (var i = 0; i < size; ++i)
            ba[i] = Next(0, uint.MaxValue) > ll;
        return ba;
    }
    public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new byte[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (byte)Next(minValue, maxValue);
        return ba;
    }
    public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ushort[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (ushort)Next(minValue, maxValue);
        return ba;
    }
    public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new uint[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (uint)Next(minValue, maxValue);
        return ba;
    }
    public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ulong[size];
        for (var i = 0; i < size; ++i)
            ba[i] = Next(minValue, maxValue);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int)Next((ulong)minLen, (ulong)maxLen)));
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte)(Sample() * byte.MaxValue + 1);
    }
    public override void GetNonZeroBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        var index = 0;
        do
        {
            var v = (byte)(Sample() * byte.MaxValue + 1);
            if (v > 0)
            {
                buffer[index] = v;
                index++;
            }
        } while (index < buffer.Length);
    }
    private unsafe ulong BufferToLong(byte[] buffer)
    {
        var len = buffer.Length;
        if (len < 1 || len > 8)
            throw new ArgumentException($"The array length {len} must be between 1 and 8");
        fixed (byte* Ptr = &buffer[0])
        {
            switch (len)
            {
                case 1:
                    return *Ptr;
                case 2:
                    return (uint)(*Ptr | (Ptr[1] << 8));
                case 3:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16));
                case 4:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24));
                case 5:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)Ptr[4] << 32);
                case 6:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8)) << 32);
                case 7:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32);
                case 8:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32);
                default:
                    return 0;
            }
        }
    }
}

(Obsolete) FixedUIntXInt.cs

Variable Bit Width Unsigned Integer Class

Jun-11,2021: Obsolete Use xIntX Instead.

[Serializable]
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    [TypeConverter(typeof(FixedUIntXIntConverter))]
    [DebuggerDisplay("{DDisplay}")]
    public class FixedUIntXInt : IComparable<FixedUIntXInt>, IComparable, IEquatable<FixedUIntXInt>, IConvertible, IFormattable
    {
        private const  int           DataSize      = sizeof(uint);
        private static int           DataBitLength = 64; //<--Change Here
        private static int           DataLength    = DataBitLength >> 5;
        public static  FixedUIntXInt Zero          = new FixedUIntXInt("0",  64);
        public static  FixedUIntXInt Ten           = new FixedUIntXInt("10", 64);
        public static  FixedUIntXInt One           = new FixedUIntXInt("1",  64);
        private        uint[]        data;
        public FixedUIntXInt(FixedUIntXInt value)
        {
            if (value == null)
                return;
            CalculateMinDataLength(value.data.Length);
            data = new uint[DataLength];
            value.data.CopyTo(data, 0);
        }
        public FixedUIntXInt(string value, int orBl)
        {
            if (orBl > 0)
                CalculateMinDataLength(orBl >> 5);
            if (!TryParse(value, out var result))
                throw new Exception("TryParse Failed.");
            data = new uint[DataLength];
            result.data.CopyTo(data, 0);
        }
        public FixedUIntXInt(byte value)
        {
            data    = new uint[DataLength];
            data[0] = value;
        }
        public FixedUIntXInt(bool value)
        {
            data    = new uint[DataLength];
            data[0] = (uint) (value ? 1 : 0);
        }
        public FixedUIntXInt(char value)
        {
            data    = new uint[DataLength];
            data[0] = value;
        }
        public FixedUIntXInt(BigDecimal value)
        {
            var ba = value.UnscaledValue.ToByteArray();
            data = new uint[DataLength];
            for (var i = 0; i < DataLength; i++)
                data[i] = BitConverter.ToUInt32(ba, i * DataSize);
        }
        public FixedUIntXInt(decimal value)
        {
            data = new uint[DataLength];
            if (value < 0)
            {
                var n = -new FixedUIntXInt(-value);
                n.data.CopyTo(data, 0);
                return;
            }
            var bits = decimal.GetBits(value);
            data[2] = (uint) bits[2];
            data[1] = (uint) bits[1];
            data[0] = (uint) bits[0];
        }
        public FixedUIntXInt(double value) : this((decimal) value)
        {
        }
        public FixedUIntXInt(float value) : this((decimal) value)
        {
        }
        public FixedUIntXInt(short value) : this((int) value)
        {
        }
        public FixedUIntXInt(int value)
        {
            data    = new uint[DataLength];
            data[0] = (uint) value;
        }
        public FixedUIntXInt(long value) : this((ulong) value)
        {
        }
        public FixedUIntXInt(sbyte value) : this((int) value)
        {
        }
        public FixedUIntXInt(ushort value)
        {
            data    = new uint[DataLength];
            data[0] = value;
        }
        public FixedUIntXInt(uint value)
        {
            data    = new uint[DataLength];
            data[0] = value;
        }
        public FixedUIntXInt(ulong value)
        {
            data    = new uint[DataLength];
            data[0] = (uint) ((value >> 32) & 0xffffffff);
            data[1] = (uint) (value         & 0xffffffff);
        }
        public FixedUIntXInt(BigInteger value) : this(value.ToByteArray())
        {
        }
        public FixedUIntXInt(Guid value) : this(value.ToByteArray())
        {
        }
        public FixedUIntXInt(byte[] value)
        {
            var minSize = value.Length / DataSize;
            if (value == null)
                throw new ArgumentNullException("value");
            var byteCount      = value.Length;
            var isNegative     = byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80;
            var unalignedBytes = byteCount % DataSize;
            var dwordCount     = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
            data = new uint[Math.Max(dwordCount, minSize)];
            if (byteCount == 0)
                return;
            int curDword, curByte, byteInDword;
            curByte = 3;
            for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
            {
                byteInDword = 0;
                while (byteInDword < DataSize)
                {
                    data[curDword] <<= 8;
                    data[curDword] |=  value[curByte];
                    curByte--;
                    byteInDword++;
                }
                curByte += 8;
            }
            if (unalignedBytes != 0)
            {
                if (isNegative)
                    data[dwordCount - 1] = 0xffffffff;
                for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
                {
                    data[curDword] <<= 8;
                    data[curDword] |=  value[curByte];
                }
            }
        }
        public FixedUIntXInt(uint[] array)
        {
            if (array == null)
                throw new Exception("Array cannot be null.");
            if (array.Length != DataLength)
                Array.Resize(ref array, DataLength);
            data = new uint[DataLength];
            var ba = new byte[4];
            for (var i = 0; i < DataLength; i++)
            {
                Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
                data[i] = BitConverter.ToUInt32(ba, 0);
            }
        }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private string DDisplay => ToString();
        public FixedUIntXInt MaxValue => (One << DataBitLength) - 1;
        public int SizeOfDataUsed
        {
            get
            {
                var dataUsed = data.Length;
                while (dataUsed > 1 && data[dataUsed - 1] == 0)
                    --dataUsed;
                if (dataUsed == 0)
                    dataUsed = 1;
                return dataUsed;
            }
        }
        public int ResetDataBitLength
        {
            get => DataBitLength;
            set
            {
                if (DataBitLength == value)
                    return;
                DataBitLength = value;
                DataLength    = DataBitLength >> 5;
                Array.Resize(ref data, DataLength);
            }
        }
        public int BitWidth
        {
            get
            {
                FixedUIntXInt bw = 1;
                var           v  = this;
                while ((v >>= 1) > 0)
                    bw++;
                if (bw < 8)
                    bw = 8;
                while (bw % 8 != 0)
                    bw++;
                return (int) bw;
            }
        }
        public bool IsOne  => this     == One;
        public bool IsEven => this % 2 == 0;
        public bool IsZero
        {
            get
            {
                for (var i = 0; i < data.Length; i++)
                    if (data[i] != 0)
                        return false;
                return true;
            }
        }
        int IComparable.CompareTo(object obj)
        {
            return Compare(this, obj);
        }
        public int CompareTo(FixedUIntXInt value)
        {
            return Compare(this, 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 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 (data[1] != 0)
                throw new OverflowException();
            return Convert.ToUInt16(data[0]);
        }
        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            if (data[1] != 0)
                throw new OverflowException();
            return Convert.ToUInt32(data[0]);
        }
        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            if (data[1] != 0)
                throw new OverflowException();
            return data[0];
        }
        public bool Equals(FixedUIntXInt obj)
        {
            if (ReferenceEquals(obj, null))
                return false;
            if (ReferenceEquals(this, obj))
                return true;
            if (data.Length != obj.data.Length)
            {
                var len = Math.Max(data.Length, obj.data.Length);
                if (data.Length < len)
                {
                    var tData = new uint[len];
                    Array.Copy(data, 0, tData, 0, data.Length);
                    data = tData;
                }
                if (obj.data.Length < len)
                    Resize(ref obj, len);
            }
            for (var i = 0; i < data.Length; i++)
                if (data[i] != obj.data[i])
                    return false;
            return true;
        }
        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 static void CalculateMinDataLength(int minSize)
        {
            if (minSize != DataLength)
            {
                DataBitLength = 32 * minSize;
                DataLength    = minSize;
            }
        }
        private static byte[] ToByteArray(ulong[] value)
        {
            var ba = new byte[value.Length << 3];
            Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3);
            return ba;
        }
        private static byte[] ToByteArray(uint[] value)
        {
            var ba = new byte[value.Length << 2];
            Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2);
            return ba;
        }
        public override int GetHashCode()
        {
            var hash = 0x811c9dc5;
            for (var i = 0; i < DataLength; i++)
            {
                hash ^= ((hash << 13) | (hash >> 19)) ^ data[i];
                hash *= 0x1000193;
            }
            return (int) hash;
        }
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        public override string ToString()
        {
            return ToString(null, null);
        }
        public string ToString(string format)
        {
            return ToString(format, null);
        }
        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 (IsZero)
                return "0";
            var          a       = new FixedUIntXInt(this);
            var          biRadix = new FixedUIntXInt(radix);
            const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz";
            var          al      = new ArrayList();
            while (a > 0)
                try
                {
                    Divide(a, biRadix, out var remainder, out var quotient);
                    al.Insert(0, charSet[(int) remainder.data[0]]);
                    a = quotient;
                }
                catch (Exception ex)
                {
                    break;
                }
            var result = new string((char[]) al.ToArray(typeof(char)));
            return result;
        }
        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 FixedUIntXInt Parse(string value)
        {
            return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
        }
        public static FixedUIntXInt Parse(string value, NumberStyles style)
        {
            return Parse(value, style, NumberFormatInfo.CurrentInfo);
        }
        public static FixedUIntXInt Parse(string value, IFormatProvider provider)
        {
            return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
        }
        public static FixedUIntXInt 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 FixedUIntXInt result)
        {
            return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
        }
        public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out FixedUIntXInt 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 FixedUIntXInt result)
        {
            result = new FixedUIntXInt(0);
            if (digits == null)
                return false;
            var multiplier = new FixedUIntXInt(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 static int Compare(FixedUIntXInt left, object right)
        {
            if (right is FixedUIntXInt)
                return Compare(left, (FixedUIntXInt) right);
            if (right is bool)
                return Compare(left, new FixedUIntXInt((bool) right));
            if (right is byte)
                return Compare(left, new FixedUIntXInt((byte) right));
            if (right is char)
                return Compare(left, new FixedUIntXInt((char) right));
            if (right is decimal)
                return Compare(left, new FixedUIntXInt((decimal) right));
            if (right is double)
                return Compare(left, new FixedUIntXInt((double) right));
            if (right is short)
                return Compare(left, new FixedUIntXInt((short) right));
            if (right is int)
                return Compare(left, new FixedUIntXInt((int) right));
            if (right is long)
                return Compare(left, new FixedUIntXInt((long) right));
            if (right is sbyte)
                return Compare(left, new FixedUIntXInt((sbyte) right));
            if (right is float)
                return Compare(left, new FixedUIntXInt((float) right));
            if (right is ushort)
                return Compare(left, new FixedUIntXInt((ushort) right));
            if (right is uint)
                return Compare(left, new FixedUIntXInt((uint) right));
            if (right is ulong)
                return Compare(left, new FixedUIntXInt((ulong) right));
            var bytes = right as byte[];
            if (bytes != null && bytes.Length != 64)
                return Compare(left, new FixedUIntXInt(bytes));
            if (right is Guid)
                return Compare(left, new FixedUIntXInt((Guid) right));
            throw new ArgumentException();
        }
        public static int Compare(FixedUIntXInt left, FixedUIntXInt right)
        {
            MakeLikeLengths(ref left, ref right);
            if (ReferenceEquals(left, right))
                return 0;
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");
            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");
            if (left > right) return 1;
            if (left == right) return 0;
            return -1;
        }
        public static implicit operator FixedUIntXInt(bool value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(byte value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(char value)
        {
            return new FixedUIntXInt(value);
        }
        public static explicit operator FixedUIntXInt(decimal value)
        {
            return new FixedUIntXInt(value);
        }
        public static explicit operator FixedUIntXInt(double value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(short value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(int value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(long value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(sbyte value)
        {
            return new FixedUIntXInt(value);
        }
        public static explicit operator FixedUIntXInt(float value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(ushort value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(uint value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(ulong value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(BigInteger value)
        {
            return new FixedUIntXInt(value);
        }
        public static implicit operator FixedUIntXInt(BigDecimal value)
        {
            return new FixedUIntXInt(value);
        }
        public static explicit operator bool(FixedUIntXInt value)
        {
            return (byte) value.data[0] != 0;
        }
        public static explicit operator byte(FixedUIntXInt value)
        {
            return (byte) value.data[0];
        }
        public static explicit operator char(FixedUIntXInt value)
        {
            return (char) (ushort) value.data[0];
        }
        public static explicit operator decimal(FixedUIntXInt value)
        {
            return new decimal((int) value.data[0], (int) value.data[1], (int) value.data[2], false, 0);
        }
        public static explicit operator double(FixedUIntXInt value)
        {
            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(FixedUIntXInt value)
        {
            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(FixedUIntXInt value)
        {
            return (short) (int) value.data[0];
        }
        public static explicit operator int(FixedUIntXInt value)
        {
            return (int) value.data[0];
        }
        public static explicit operator long(FixedUIntXInt value)
        {
            if (value.data[1] != 0)
                return (long) (((ulong) value.data[1] << 32) | value.data[0]);
            return value.data[0];
        }
        public static explicit operator uint(FixedUIntXInt value)
        {
            return value.data[0];
        }
        public static explicit operator ushort(FixedUIntXInt value)
        {
            return (ushort) value.data[0];
        }
        public static explicit operator ulong(FixedUIntXInt value)
        {
            if (value.data[1] != 0)
                return ((ulong) value.data[1] << 32) | value.data[0];
            return value.data[0];
        }
        public static explicit operator BigInteger(FixedUIntXInt value)
        {
            return new BigInteger(value.ToByteArray());
        }
        public static bool operator >(FixedUIntXInt left, FixedUIntXInt right)
        {
            MakeLikeLengths(ref left, ref right);
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");
            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");
            for (var i = 0; i < DataLength; i++)
                if (left.data[i] != right.data[i])
                    return left.data[i] > right.data[i];
            return false;
        }
        private static void MakeLikeLengths(ref FixedUIntXInt left, ref FixedUIntXInt right)
        {
            if (left.data.Length != right.data.Length)
            {
                var len = Math.Max(left.data.Length, right.data.Length);
                Resize(ref left,  len);
                Resize(ref right, len);
            }
        }
        private static void Resize(ref FixedUIntXInt value, int newSize)
        {
            var nData = new uint[newSize];
            var len   = value.data.Length;
            for (var i = 0; i < len; i++)
                nData[i] = value.data[i];
            value.data = (uint[]) nData.Clone();
        }
        public static bool operator <(FixedUIntXInt left, FixedUIntXInt right)
        {
            return Compare(left, right) < 0;
        }
        public static bool operator >=(FixedUIntXInt left, FixedUIntXInt right)
        {
            return Compare(left, right) >= 0;
        }
        public static bool operator <=(FixedUIntXInt left, FixedUIntXInt right)
        {
            return Compare(left, right) <= 0;
        }
        public static bool operator !=(FixedUIntXInt left, FixedUIntXInt right)
        {
            return Compare(left, right) != 0;
        }
        public static bool operator ==(FixedUIntXInt left, FixedUIntXInt right)
        {
            if (ReferenceEquals(left, right))
                return true;
            if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
                return false;
            return left.Equals(right);
        }
        public static FixedUIntXInt operator +(FixedUIntXInt value)
        {
            return value;
        }
        public static FixedUIntXInt operator ~(FixedUIntXInt value)
        {
            var da = new uint[DataLength];
            for (var idx = 0; idx < DataLength; idx++)
                da[idx] = ~value.data[idx];
            return new FixedUIntXInt(da);
        }
        public static FixedUIntXInt operator -(FixedUIntXInt value)
        {
            return Negate(value);
        }
        public static FixedUIntXInt operator ++(FixedUIntXInt value)
        {
            return value + 1;
        }
        public static FixedUIntXInt operator --(FixedUIntXInt value)
        {
            return value - 1;
        }
        public static FixedUIntXInt Negate(FixedUIntXInt value)
        {
            for (var i = 0; i < DataLength; i++)
                value.data[i] = ~value.data[i];
            return new FixedUIntXInt(value);
        }
        public static FixedUIntXInt operator +(FixedUIntXInt left, FixedUIntXInt right)
        {
            var  dl     = left.data.Length > right.data.Length ? left.data.Length : right.data.Length;
            var  result = new uint[dl];
            long carry  = 0;
            for (var i = 0; i < dl; i++)
            {
                var sum = left.data[i] + (long) right.data[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 FixedUIntXInt(result);
        }
        public static FixedUIntXInt operator -(FixedUIntXInt left, FixedUIntXInt right)
        {
            var  size  = Math.Max(left.data.Length, right.data.Length) + 1;
            var  da    = new uint[size];
            long carry = 0;
            for (var i = 0; i < da.Length - 1; i++)
            {
                var diff = left.data[i] - (long) right.data[i] - carry;
                da[i] = (uint) (diff & DigitsArray.AllBits);
                carry = diff < 0 ? 1 : 0;
            }
            return new FixedUIntXInt(da);
        }
        public static FixedUIntXInt Add(FixedUIntXInt left, FixedUIntXInt right)
        {
            return left + right;
        }
        public static FixedUIntXInt Subtract(FixedUIntXInt left, FixedUIntXInt right)
        {
            return left - right;
        }
        public static FixedUIntXInt Divide(FixedUIntXInt dividend, FixedUIntXInt divisor)
        {
            return DivRem(dividend, divisor, out var integer);
        }
        public static void Divide(FixedUIntXInt dividend, FixedUIntXInt divisor, out FixedUIntXInt remainder, out FixedUIntXInt quotient)
        {
            if (divisor == 0)
                throw new DivideByZeroException();
            DivRem(dividend.data, divisor.data, out var quo, out var rem);
            remainder = new FixedUIntXInt(rem);
            quotient  = new FixedUIntXInt(quo);
        }
        public static FixedUIntXInt DivRem(FixedUIntXInt dividend, FixedUIntXInt divisor, out FixedUIntXInt remainder)
        {
            if (divisor == 0)
                throw new DivideByZeroException();
            DivRem(dividend.data, divisor.data, out var quotient, out var rem);
            remainder = new FixedUIntXInt(rem);
            return new FixedUIntXInt(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[1];
            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 FixedUIntXInt Remainder(FixedUIntXInt dividend, FixedUIntXInt divisor)
        {
            DivRem(dividend, divisor, out var remainder);
            return remainder;
        }
        public static FixedUIntXInt Max(FixedUIntXInt left, FixedUIntXInt right)
        {
            return left.CompareTo(right) < 0 ? right : left;
        }
        public static FixedUIntXInt Min(FixedUIntXInt left, FixedUIntXInt right)
        {
            return left.CompareTo(right) <= 0 ? left : right;
        }
        public static int GetBitWidth(FixedUIntXInt n)
        {
            FixedUIntXInt bw = 1;
            var           v  = n;
            while ((v >>= 1) > 0)
                bw++;
            if (bw < 8)
                bw = 8;
            while (bw % 8 != 0)
                bw++;
            return (int) bw;
        }
        public static FixedUIntXInt operator %(FixedUIntXInt dividend, FixedUIntXInt divisor)
        {
            return Remainder(dividend, divisor);
        }
        public static FixedUIntXInt operator /(FixedUIntXInt dividend, FixedUIntXInt divisor)
        {
            return Divide(dividend, divisor);
        }
        public ulong[] ToUIn64Array()
        {
            var al = data.Length >> 1;
            if (al * 2 != data.Length)
                al++;
            var arr = new ulong[al];
            Buffer.BlockCopy(data, 0, arr, 0, data.Length << 2);
            return arr;
        }
        public uint[] ToUIn32Array()
        {
            return data;
        }
        public byte[] ToByteArray()
        {
            var ba = new byte[data.Length * DataSize];
            Buffer.BlockCopy(data, 0, ba, 0, data.Length * DataSize);
            return ba;
        }
        public byte[] ToByteArray(int length)
        {
            if (length <= 0 || length > data.Length * DataSize)
                throw new ArgumentException($"Length {length} out of range length > 0 or length <= {data.Length * DataSize}");
            var ba = new byte[length];
            Buffer.BlockCopy(data, 0, ba, 0, length);
            return ba;
        }
        public static FixedUIntXInt Multiply(FixedUIntXInt left, FixedUIntXInt right)
        {
            var xInts   = left.data;
            var yInts   = right.data;
            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 FixedUIntXInt(mulInts);
        }
        public static FixedUIntXInt operator *(FixedUIntXInt left, FixedUIntXInt right)
        {
            return Multiply(left, right);
        }
        public static FixedUIntXInt operator >>(FixedUIntXInt value, int shift)
        {
            if (value == Zero)
                return Zero;
            var xd          = (uint[]) value.data.Clone();
            var shiftAmount = 32;
            var invShift    = 0;
            var bufLen      = xd.Length;
            while (bufLen > 1 && xd[bufLen - 1] == 0)
                bufLen--;
            for (var count = shift; count > 0; count -= shiftAmount)
            {
                if (count < shiftAmount)
                {
                    shiftAmount = count;
                    invShift    = 32 - shiftAmount;
                }
                ulong carry = 0;
                for (var i = bufLen - 1; i >= 0; i--)
                {
                    var val = (ulong) xd[i] >> shiftAmount;
                    val   |= carry;
                    carry =  (ulong) xd[i] << invShift;
                    xd[i] =  (uint) val;
                }
            }
            return new FixedUIntXInt(xd);
        }
        public static FixedUIntXInt operator <<(FixedUIntXInt value, int shift)
        {
            if (value == Zero)
                return Zero;
            var digitShift = shift / 32;
            var smallShift = shift - digitShift * 32;
            var xd         = (uint[]) value.data.Clone();
            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 FixedUIntXInt(zd);
        }
        public static FixedUIntXInt operator |(FixedUIntXInt left, FixedUIntXInt right)
        {
            if (left == 0)
                return right;
            if (right == 0)
                return left;
            var z = new uint[Math.Max(left.data.Length, right.data.Length)];
            for (var i = 0; i < z.Length; i++)
            {
                var xu = i < left.data.Length ? left.data[i] : 0U;
                var yu = i < right.data.Length ? right.data[i] : 0U;
                z[i] = xu | yu;
            }
            return new FixedUIntXInt(z);
        }
        public static FixedUIntXInt operator ^(FixedUIntXInt left, FixedUIntXInt right)
        {
            var z = new uint[Math.Max(left.data.Length, right.data.Length)];
            for (var i = 0; i < z.Length; i++)
            {
                var xu = i < left.data.Length ? left.data[i] : 0U;
                var yu = i < right.data.Length ? right.data[i] : 0U;
                z[i] = xu ^ yu;
            }
            return new FixedUIntXInt(z);
        }
        public static FixedUIntXInt operator &(FixedUIntXInt left, FixedUIntXInt right)
        {
            if (left == 0 || right == 0)
                return Zero;
            var z = new uint[Math.Max(left.data.Length, right.data.Length)];
            for (var i = 0; i < z.Length; i++)
            {
                var xu = i < left.data.Length ? left.data[i] : 0U;
                var yu = i < right.data.Length ? right.data[i] : 0U;
                z[i] = xu & yu;
            }
            return new FixedUIntXInt(z);
        }
        private class FixedUIntXIntConverter : 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 FixedUIntXInt("0", 64);
            }
            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);
            }
        }
    }

LongLong.cs

Int64 Bit Class

Jun-11,2021: Obsolete Use xIntX Instead.

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

(Obsolete) Int512.cs

Int512 Bit Class

Jun-11,2021: Obsolete Use xIntX Instead.

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

(Obsolete) Int256.cs

Int256 Bit Class

Jun-11,2021: Obsolete Use xIntX Instead.

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

ConcurrencyCheck.cs

Check and Store Concurrency Usage

Updated: Dec-25,2020

using System;
using System.Diagnostics;
using System.Threading;
public class ConcurrencyCheck
{
    public volatile ConcurrencyInfo ConcurrencyInformation = new ConcurrencyInfo();
    private static  int             ProcessorCount => Environment.ProcessorCount;
    public bool OverrideAutoConcurrency
    {
        get;
        set;
    }
    public bool QuickCheck
    {
        get;
        set;
    } = false;
    public bool UsingConcurrency
    {
        get;
        private set;
    }
    public bool CheckState()
    {
        if (OverrideAutoConcurrency)
            return false;
        if (QuickCheck && ConcurrencyInformation.Calls > ProcessorCount && ConcurrencyInformation.LockState == 0)
            return false;
        if (ConcurrencyInformation.StatusThreadId != Thread.CurrentThread.ManagedThreadId)
        {
            ConcurrencyInformation.StatusThreadId = Thread.CurrentThread.ManagedThreadId;
            ConcurrencyInformation.Add(ConcurrencyInformation.StatusThreadId);
        }
        if (ConcurrencyInformation.LockState == 1)
            return true;
        if (ConcurrencyInformation.BeginningThreadId == 0 && ConcurrencyInformation.LockState == 0 && Thread.CurrentThread.ManagedThreadId != 0)
            ConcurrencyInformation.BeginningThreadId = Thread.CurrentThread.ManagedThreadId;
        if (ConcurrencyInformation.LockState == 0)
            if (ConcurrencyInformation.BeginningThreadId != Thread.CurrentThread.ManagedThreadId)
            {
                ConcurrencyInformation.LockState = 1;
                UsingConcurrency                 = true;
                return true;
            }
        Interlocked.Increment(ref ConcurrencyInformation.Calls);
        return false;
    }
    [DebuggerDisplay("UniqueThreadIds = {ActiveThreads}")]
    public class ConcurrencyInfo
    {
        public volatile int     ActiveThreads;
        public volatile int     BeginningThreadId;
        public volatile int     Calls;
        public volatile int     LockState;
        public volatile int     StatusThreadId;
        public volatile bool[]  UniqueThreadIds = new bool[32768];
        public void Add(int value)
        {
            if (!UniqueThreadIds[value])
            {
                UniqueThreadIds[value] = true;
                Interlocked.Increment(ref ActiveThreads);
                return;
            }
        }
    }
}

ZOB64.cs

Example Zobrist Hashing 64-Bit

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
/// <summary>
///     
///     https://en.wikipedia.org/wiki/Zobrist_hashing
///    
/// </summary>
public class ZOB64 : HashAlgorithm
{
    private readonly ulong      starthash = 0x391615744853B307;
    private          ulong[]    _table;
    private          ulong      hash;
    private          uint       hash32;
    private          ZOB32State zhs;
    public ZOB64()
    {
        hash = starthash;
        BuildTable(0x7965CBDDD4A9E7AF);
    }
    public override int HashSize => 64;
    public override void Initialize()
    {
        hash = starthash;
    }
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        Hash64(bytes, ibStart, cbSize);
    }
    private static ulong RotateLeft(ulong value, int count)
    {
        return(value << count) | (value >> (64 - count % 64));
    }
    private unsafe void Hash64(byte[] bytes, int ibStart, int cbSize)
    {
        if(bytes == null)
            return;
        if(ibStart >= bytes.Length || cbSize > bytes.Length)
            return;
        var i = 1;
        fixed(byte* pb = bytes)
        {
            var nb = pb + ibStart;
            while(cbSize >= 1)
            {
                hash   ^= RotateLeft(_table[*nb], i++);
                nb     += 1;
                cbSize -= 1;
            }
        }
    }
    protected override byte[] HashFinal()
    {
        zhs.hash64 = hash;
        hash32     = zhs.hi ^ zhs.lo;
        return hash.GetBytes();
    }
    public void BuildTable(ulong seed)
    {
        var s1   = (int) seed;
        var s2   = (int) (seed >> 32);
        var rnd  = new Random(s1);
        var rnd1 = new Random(s2);
        var tt   = new DynHashSet32<ulong>();
        _table = new ulong[256];
        var u = new ZOB32State();
        for(var i = 0; i < 256; i++)
        {
            ulong v;
            do
            {
                u.hi = (uint) rnd.Next();
                u.lo = (uint) rnd1.Next();
                v    = u.hash64;
            } while(tt.Contains(v));
            tt.Add(v);
            _table[i] = v;
        }
    }
    [StructLayout(LayoutKind.Explicit)]
    public struct ZOB32State
    {
        [FieldOffset(0)] public ulong hash64;
        [FieldOffset(0)] public uint  lo;
        [FieldOffset(4)] public uint  hi;
    }
}

KSM128.cs

Re-Work of the Sha3 Keccak Sponge for 128 Bit Hashing

using System;
using System.Runtime.CompilerServices;
public class KSM128 : HashAlgorithmEx
{
    private readonly int _outputLength;
    private readonly int _rateBytes;
    private readonly ulong[] _roundConstants =
    {
        0x0000000000000001,
        0x0000000000008082,
        0x800000000000808A,
        0x8000000080008000,
        0x000000000000808B,
        0x0000000080000001,
        0x8000000080008081,
        0x8000000000008009,
        0x000000000000008A,
        0x0000000000000088,
        0x0000000080008009,
        0x000000008000000A,
        0x000000008000808B,
        0x800000000000008B,
        0x8000000000008089,
        0x8000000000008003,
        0x8000000000008002,
        0x8000000000000080,
        0x000000000000800A,
        0x800000008000000A,
        0x8000000080008081,
        0x8000000000008080,
        0x0000000080000001,
        0x8000000080008008
    };
    private readonly ulong[] _seed;
    private          int     _blockSize;
    private          int     _input;
    private          int     _output;
    private          byte[]  _result;
    private          ulong[] _state;
    public           int     HashLength;
    public           int     Rounds = 24;
    public KSM128(int size, int rounds = 24, ulong[] seed = null)
    {
        if (rounds > 24)
            throw new Exception($"Maximum rounds allowed is {24}");
        var MaxBR     = (64 >> 3) * 5;
        var sizeBytes = size >> 3;
        var rateBytes = MaxBR - (sizeBytes << 1);
        var MaxSize   = ((MaxBR - 8)       >> 1) << 3;
        if (rateBytes < 8)
            throw new Exception($"Maximum size allowed is {MaxSize} Bits with {128} bit Width specified. Specified Size is {size} Bits.");
        var outputLength = size >> 3;
        _rateBytes    = rateBytes;
        _outputLength = outputLength;
        HashLength    = outputLength;
        _seed         = seed;
    }
    public override void Initialize()
    {
        _blockSize = 0;
        _input     = 0;
        _output    = 0;
        _state     = new ulong[5];
        _result    = new byte[_outputLength];
        if (_seed != null && _seed[0] != 0)
        {
            for (var i = 0; i < _seed.Length && i < _state.Length; ++i)
                _state[i] = _seed[i];
            Permute(_state);
        }
    }
    public void Absorb(byte[] array, int start, int size)
    {
        while (size > 0)
        {
            _blockSize = Math.Min(size, _rateBytes);
            for (var index = start; index < _blockSize; ++index)
            {
                var num = Convert.ToByte(Buffer.GetByte(_state, index) ^ array[index + _input]);
                Buffer.SetByte(_state, index, num);
            }
            _input += _blockSize;
            size   -= _blockSize;
            if (_blockSize == _rateBytes)
            {
                Permute(_state);
                _blockSize = 0;
            }
        }
    }
    public byte[] Squeeze()
    {
        Buffer.SetByte(_state, _blockSize,     Convert.ToByte(Buffer.GetByte(_state, _blockSize)     ^ 6));
        Buffer.SetByte(_state, _rateBytes - 1, Convert.ToByte(Buffer.GetByte(_state, _rateBytes - 1) ^ 128));
        Permute(_state);
        var outputLength = _outputLength;
        while (outputLength > 0)
        {
            _blockSize = Math.Min(outputLength, _rateBytes);
            Buffer.BlockCopy(_state, 0, _result, _output, _blockSize);
            _output      += _blockSize;
            outputLength -= _blockSize;
            if (outputLength > 0)
                Permute(_state);
        }
        return _result;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void Permute(ulong[] state)
    {
        for (var round = 0; round < Rounds; ++round)
        {
            Theta(out var C0, state, out var C1, out var C2, out var C3, out var C4);
            RhoPi(state);
            Chi(ref C0, state, ref C1, ref C2, ref C3, ref C4);
            Iota(round, state);
        }
    }
    private static void Theta(out ulong C0, ulong[] state, out ulong C1, out ulong C2, out ulong C3, out ulong C4)
    {
        C0 = state[0] ^ state[4];
        C1 = state[1] ^ state[0];
        C2 = state[2] ^ state[1];
        C3 = state[3] ^ state[2];
        C4 = state[4] ^ state[3];
        var D0 = Rol(C1, 1) ^ C4;
        var D1 = Rol(C2, 1) ^ C0;
        var D2 = Rol(C3, 1) ^ C1;
        var D3 = Rol(C4, 1) ^ C2;
        var D4 = Rol(C0, 1) ^ C3;
        state[0] ^= D0;
        state[1] ^= D1;
        state[2] ^= D2;
        state[3] ^= D3;
        state[4] ^= D4;
    }
    private static void RhoPi(ulong[] state)
    {
        var a = Rol(state[1], 1);
        state[1] = Rol(state[4], 44);
        state[4] = Rol(state[3], 43);
        state[3] = Rol(state[2], 14);
        state[4] = Rol(state[1], 21);
        state[2] = a;
    }
    private void Iota(int round, ulong[] state)
    {
        state[0] ^= _roundConstants[round];
    }
    private static void Chi(ref ulong C0, ulong[] state, ref ulong C1, ref ulong C2, ref ulong C3, ref ulong C4)
    {
        C0       = state[0] ^ (~state[1] & state[2]);
        C1       = state[1] ^ (~state[2] & state[3]);
        C2       = state[2] ^ (~state[3] & state[4]);
        C3       = state[3] ^ (~state[4] & state[0]);
        C4       = state[4] ^ (~state[0] & state[1]);
        state[0] = C0;
        state[1] = C1;
        state[2] = C2;
        state[3] = C3;
        state[4] = C4;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong Rol(ulong x, byte y)
    {
        return (x << y) | (x >> (64 - y));
    }
    protected override void HashCore(byte[] array, int ibStart, int cbSize)
    {
        Initialize();
        Absorb(array, ibStart, cbSize);
    }
    protected override byte[] HashFinal()
    {
        return Squeeze();
    }
}