CcArray.cs

Concurrent Array (Ordered) Class with Indexing, and without Blocking

Updated: Aug-2,2021

        RandomBigInt rng  = new RandomBigInt(64);
        ulong[]      sla1 = Enumerable.Range(0, 1000000).AsParallel().WithDegreeOfParallelism(10).Select(i => (ulong)rng.Next()).ToArray();
        CcArray<ulong> ccl = new CcArray<ulong>(1000000);

Example 1:       
        Parallel.ForEach(sla1, new ParallelOptions { MaxDegreeOfParallelism = 10 }, (v, p, i) =>
        {
            ccl.Add(v, (int)i);
        });

Example 2:
        Parallel.For(0,sla1.Length,i=>
        {
            ccl.Add(sla1[i], (int)i);
        });

Example 3:
        sla1.AsEnumerable().Select( (v,i)=> new {value=v,index=i}).AsParallel().WithDegreeOfParallelism(10).ForAll(x=>
        {
            ccl[x.index] = x.value;
        });

       Var asa = new ulong[1000000];
       for (var i = 0; i < 1000000; ++i)
          asa[i] = ccl[i];
       var exc = sla1.Except(asa).ToArray();
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcArray<T> : IEnumerable<T>
{
    private readonly int           _size;
    private volatile int           _activeThreadPosition;
    private volatile int[]         _activeThreads;
    private volatile IntSet18<T>[] _array;
    public volatile  int           NumberOfActiveThreads;
    public CcArray(int size)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new IntSet18<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _activeThreadPosition = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public T this[int index]
    {
        get
        {
            var (idx, trd) = FindIndex(index);
            return idx != -1 ? _array[trd].Slots[idx].Value : default;
        }
        set
        {
            var (idx, trd) = FindIndex(index);
            if (idx != -1)
                _array[trd].Slots[idx].Value = value;
            else Add(value, index);
        }
    }
    public int Count
    {
        get
        {
            if (_activeThreads == null)
                throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]].Allocated)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public void Add(T item, int index, bool updateValue = false)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var id = ProcessThread();
        var (idx, trd) = FindIndex(index);
        if (idx == -1)
            _array[id].Add(index, item);
        else if (updateValue)
            _array[trd].Slots[idx].Value = item;
    }
    public (int idx, int trd) FindIndex(int index)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                {
                    var idx = _array[_activeThreads[i]].FindKey(index);
                    if (idx != -1)
                        return (idx, _activeThreads[i]);
                }
        return (-1, -1);
    }
    private int ProcessThread()
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (!_array[id].Allocated)
        {
            Interlocked.Increment(ref NumberOfActiveThreads);
            _array[id] = new IntSet18<T>(_size / NumberOfActiveThreads);
            if (_activeThreadPosition >= _activeThreads.Length)
            {
                var newActiveThreads = new int[_activeThreads.Length << 1];
                newActiveThreads.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        newActiveThreads[i] = _activeThreads[i];
                _activeThreads = newActiveThreads;
            }
            _activeThreads[_activeThreadPosition] = id;
            Interlocked.Increment(ref _activeThreadPosition);
        }
        return id;
    }
    public bool Contains(T item)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var eComparer = EqualityComparer<T>.Default;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                    for (var j = 0; j < _array[_activeThreads[i]].Count; ++j)
                        if (eComparer.Equals(_array[_activeThreads[i]].Slots[j].Value, item))
                            return true;
        return false;
    }
    public T[] ToArray()
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var outputArray = new T[Count];
        var ptr         = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                    foreach (var v in _array[_activeThreads[i]])
                        outputArray[ptr++] = v.Value;
        return outputArray;
    }
    private IEnumerator<T> GetEnum()
    {
        var array = ToArray();
        foreach (var i in array)
            yield return i;
    }
    [DebuggerDisplay("Count = {" + nameof(Count) + "}")]
    internal struct IntSet18<T1>
    {
        private  int[]  _buckets;
        internal Slot[] Slots;
        public   bool   Allocated;
        public IntSet18(int size)
        {
            _buckets  = new int[size];
            Slots     = new Slot[size];
            Count     = 0;
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public IEnumerator<KeyValuePair<int, T1>> GetEnumerator()
        {
            for (var i = 0; i < Count; i++)
                if (Slots[i].Key >= 0)
                    yield return new KeyValuePair<int, T1>(Slots[i].Key, Slots[i].Value);
        }
        public bool Add(int key, T1 value)
        {
            if (FindKey(key) != -1)
                return true;
            if (Count >= Slots.Length)
                Resize();
            var pos = key % _buckets.Length;
            Slots[Count].Next  = _buckets[pos] - 1;
            Slots[Count].Key   = key;
            Slots[Count].Value = value;
            _buckets[pos]      = Count + 1;
            ++Count;
            return false;
        }
        private void Resize()
        {
            var newSize    = _buckets.Length + _buckets.Length / 4 * 3;
            var newSlots   = new Slot[newSize];
            var newBuckets = new int[newSize];
            var newCount   = 0;
            var en         = GetEnumerator();
            while (en.MoveNext())
            {
                var key   = en.Current.Key;
                var value = en.Current.Value;
                var pos   = key % newBuckets.Length;
                newSlots[newCount].Next  = newBuckets[pos] - 1;
                newSlots[newCount].Key   = key;
                newSlots[newCount].Value = value;
                newBuckets[pos]          = newCount + 1;
                ++newCount;
            }
            Slots    = newSlots;
            _buckets = newBuckets;
            Count    = newCount;
        }
        public int FindKey(int key)
        {
            for (var position = _buckets[key % _buckets.Length] - 1; position >= 0; position = Slots[position].Next)
                if (Equals(Slots[position].Key, key))
                    return position;
            return -1;
        }
        internal struct Slot
        {
            public int Next;
            public int Key;
            public T1  Value;
        }
    }
}

CcDictionary.cs

Concurrent Dictionary Class without Blocking

Updated: July-27,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    private readonly int                     _size;
    private volatile int[]                   _activeThreads;
    private          DicA<TKey, TValue>[]    _array;
    private volatile int                     _bP;
    internal         IEqualityComparer<TKey> _comparer;
    public volatile  int                     NumberOfActiveThreads;
    public CcDictionary() : this(1024, null)
    {
    }
    public CcDictionary(int size) : this(size, null)
    {
    }
    public CcDictionary(int size, IEqualityComparer<TKey> comparer)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new DicA<TKey, TValue>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
        if (comparer == null)
            _comparer = EqualityComparer<TKey>.Default;
        else
            _comparer = comparer;
    }
    public CcDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, int concurrencyLevel = 0)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array = new DicA<TKey, TValue>[nW];
        var col = collection.ToList();
        _size                 = col.Count;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
        _comparer = EqualityComparer<TKey>.Default;
        var ccl = Environment.ProcessorCount;
        if (concurrencyLevel != 0)
            ccl = concurrencyLevel;
        col.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>
        {
            Add(i.Key, i.Value);
        });
    }
    public int Count
    {
        get
        {
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]] != null)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    public TValue this[TKey key]
    {
        get
        {
           ProcessThread();
            var rv = FindKey(key);
            return rv.idx != -1 ? _array[rv.trd][key] : default;
        }
        set => Add(key, value, true);
    }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return GetEnum();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public bool TryGetValue(TKey key, out TValue value)
    {
        var (idx, trd) = FindKey(key);
        if (idx == -1)
        {
            value = default;
            return false;
        }
        value = _array[trd][key];
        return true;
    }
    public void Clear()
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new DicA<TKey, TValue>[nW];
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public void AddRange(IEnumerable<KeyValuePair<TKey, TValue>> collection, int concurrencyLevel = 0)
    {
        var ccl = Environment.ProcessorCount;
        if (concurrencyLevel != 0)
            ccl = concurrencyLevel;
        collection.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>
        {
            Add(i.Key, i.Value);
        });
    }
    public void Add(TKey key, TValue value, bool updateValue = false)
    {
        var id  = ProcessThread();
        var idx = FindKey(key);
        if (idx.idx == -1)
            _array[id].Add(key, value);
        else if (updateValue)
            _array[idx.trd].Values[idx.idx] = value;
    }
    private int ProcessThread()
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (_array[id] == null)
        {
            _array[id] = new DicA<TKey, TValue>(_size, _comparer);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        return id;
    }
    public bool TryAdd(TKey key, TValue value)
    {
        Add(key, value);
        return true;
    }
    public bool ContainsKey(TKey key)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    if (_array[_activeThreads[i]].ContainsKey(key))
                        return true;
        return false;
    }
    public bool ContainsValue(TValue value)
    {
        var eComparer = EqualityComparer<TValue>.Default;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    for (var j = 0; j < _array[_activeThreads[i]].Count; ++j)
                        if (eComparer.Equals(_array[_activeThreads[i]].Values[j], value))
                            return true;
        return false;
    }
    public (int idx, int trd) FindKey(TKey key)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                {
                    var idx = _array[_activeThreads[i]].FindKeyIndex(key);
                    if (idx != -1)
                        return (idx, _activeThreads[i]);
                }
        return (-1, -1);
    }
    public bool Remove(TKey key)
    {
        var (idx, trd) = FindKey(key);
        if (idx == -1)
            return false;
        _array[_activeThreads[trd]].Remove(key);
        return true;
    }
    private IEnumerator<KeyValuePair<TKey, TValue>> GetEnum()
    {
        foreach (var i in ToArray())
            yield return new KeyValuePair<TKey, TValue>(i.Key, i.Value);
    }
    public KeyValuePair<TKey, TValue>[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    totalCount += _array[_activeThreads[i]].Count;
        var ta  = new KeyValuePair<TKey, TValue>[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    foreach (var v in _array[_activeThreads[i]])
                        ta[ptr++] = new KeyValuePair<TKey, TValue>(v.Key, v.Value);
        return ta;
    }
    public class DicA<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
    {
        public MSet15<TKey> Keys;
        public int          Resizes;
        public TValue[]     Values;
        public DicA() : this(101, EqualityComparer<TKey>.Default)
        {
        }
        public DicA(int size) : this(size, EqualityComparer<TKey>.Default)
        {
        }
        public DicA(int size, IEqualityComparer<TKey> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;
            Keys          = new MSet15<TKey>(size);
            Values        = new TValue[size];
            Keys.Comparer = comparer;
        }
        public DicA(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer = null)
        {
            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;
            Keys.Comparer = comparer;
            foreach (var kp in collection)
                Add(kp.Key, kp.Value);
        }
        public int Count => Keys.Count;
        public TValue this[TKey key]
        {
            get
            {
                var pos = Keys.FindEntry(key);
                return pos == -1 ? default : Values[pos];
            }
            set => Add(key, value);
        }
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            for (var i = 0; i < Count; i++)
                if (Keys.Slots[i].HashCode > 0)
                    yield return new KeyValuePair<TKey, TValue>(Keys.Slots[i].Value, Values[i]);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public bool Add(TKey key, TValue value)
        {
            if (!Keys.Add(key))
            {
                if (Values.Length != Keys.Slots.Length)
                {
                    var nValues = new TValue[Keys.Slots.Length];
                    Array.Copy(Values, nValues, Values.Length);
                    Values = nValues;
                    Resizes++;
                }
                Values[Keys.Position] = value;
                return false;
            }
            Values[Keys.Position] = value;
            return true;
        }
        public void Remove(TKey key)
        {
            var pos = Keys.FindEntry(key);
            if (pos != -1)
            {
                Values[pos] = default;
                Keys.Remove(key);
            }
        }
        public bool ContainsKey(TKey key)
        {
            return Keys.FindEntry(key) != -1;
        }
        public int FindKeyIndex(TKey key)
        {
            return Keys.FindEntry(key);
        }
    }
}

CcHashSet.cs

Concurrent HashSet Class without Blocking

Updated: July-23,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcHashSet<T> : IEnumerable
{
    private readonly HashSet<T>[]         _array;
    private readonly int                  _size;
    private volatile int[]                _activeThreads;
    private volatile int                  _bP;
    private readonly IEqualityComparer<T> _comparer;
    public volatile  int                  NumberOfActiveThreads;
    public CcHashSet() : this(1024, null)
    {
    }
    public CcHashSet(int size) : this(size, null)
    {
    }
    public CcHashSet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            _comparer = EqualityComparer<T>.Default;
        else
            _comparer = comparer;
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new HashSet<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public int Count
    {
        get
        {
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]] != null)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public void Add(T item)
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (_array[id] == null)
        {
            _array[id] = new HashSet<T>(_size, _comparer);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        if (!Contains(item))
            _array[id].Add(item);
    }
    public bool Contains(T item)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    if (_array[_activeThreads[i]].Contains(item))
                        return true;
        return false;
    }
    public IEnumerator<T> GetEnum()
    {
        var arr = ToArray();
        foreach (var i in arr)
            yield return i;
    }
    public T[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    totalCount += _array[_activeThreads[i]].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                {
                    var it = _array[_activeThreads[i]].ToArray();
                    for (var j = 0; j < it.Length; ++j)
                        ta[ptr++] = it[j];
                }
        return ta;
    }
}

CcCollection.cs

Concurrent Collection Class without Blocking

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcCollection<T> : IEnumerable<T>
{
    private readonly IntA<T>[] _array;
    private readonly int       _size;
    private volatile int[]     _activeThreads;
    private volatile int       _bP;
    public volatile  int       NumberOfActiveThreads;
    public CcCollection() : this(1024)
    {
    }
    public CcCollection(int size)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new IntA<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public int Count
    {
        get
        {
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]].Allocated)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public void Add(T item)
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (!_array[id].Allocated)
        {
            _array[id] = new IntA<T>(_size);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        _array[id].Add(item);
    }
    public IEnumerator<T> GetEnum()
    {
        var arr = ToArray();
        foreach (var i in arr)
            yield return i;
    }
    public T[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                    totalCount += _array[_activeThreads[i]].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                {
                    var it = _array[_activeThreads[i]].ToArray();
                    for (var j = 0; j < it.Length; ++j)
                        ta[ptr++] = it[j];
                }
        return ta;
    }
    internal struct IntA<T> : IEnumerable<T>
    {
        private T[]  _array;
        public  bool Allocated;
        public IntA(int cap)
        {
            Count     = 0;
            _array    = new T[cap];
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public int Length => _array.Length;
        public T this[int index]
        {
            get
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                return _array[index];
            }
            set
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                _array[index] = value;
            }
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Add(T item)
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, _array.Length << 1);
            _array[Count] = item;
            Count++;
        }
        public T[] ToArray()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            return newtArray;
        }
        public void Trim()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            _array = newtArray;
        }
        public void Clear()
        {
            Array.Clear(_array, 0, Count);
            Count = 0;
        }
        public void Zero()
        {
            _array = Array.Empty<T>();
            Count  = 0;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return GetEnum();
        }
        public IEnumerator<T> GetEnum()
        {
            for (var i = 0; i < Count; i++)
                yield return _array[i];
        }
    }
}

SegmentedArray.cs

Segmented Array Class

I wrote this array class while investigating the error curve in Prime Number Theorem. I wanted to avoid using blocking while using parallel invoke, while using as little memory as possible.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public struct SegmentedArray<T>
{
    private readonly IntA<T>[] _array;
    private readonly int       _size;
    public SegmentedArray(int length, int size)
    {
        _array = new IntA<T>[16];
        _size  = size;
    }
    public void Add(T item, int index, long range, long total)
    {
        if (!_array[index].Allocated)
            _array[index] = new IntA<T>(_size);
        var density = (float)_array[index].Count / range;
        var ssic    = total                      * density;
        _array[index].Add(item, (int)ssic);
    }
    public T[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < 16; ++i)
            if (_array[i].Allocated)
                totalCount += _array[i].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < 16; ++i)
            if (_array[i].Allocated)
            {
                var it = _array[i].ToArray();
                _array[i].Zero();
                for (var j = 0; j < it.Length; ++j)
                    ta[ptr++] = it[j];
            }
        return ta;
    }
    [DebuggerDisplay("Count = {Count}")]
    internal struct IntA<T> : IEnumerable<T>
    {
        internal T[]  _array;
        internal bool Allocated;
        public IntA(int cap)
        {
            Count     = 0;
            _array    = new T[cap];
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public T this[int index]
        {
            get
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                return _array[index];
            }
            set
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                _array[index] = value;
            }
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Add(T item, int suggestedSize)
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, suggestedSize);
            _array[Count] = item;
            Count++;
        }
        public T[] ToArray()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            return newtArray;
        }
        public void Clean()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            _array = newtArray;
        }
        public void Clear()
        {
            Array.Clear(_array, 0, Count);
            Count = 0;
        }
        public void Zero()
        {
            _array = Array.Empty<T>();
            Count  = 0;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return GetEnum();
        }
        public IEnumerator<T> GetEnum()
        {
            for (var i = 0; i < Count; i++)
                yield return _array[i];
        }
    }
}

SegmentedHashSet.cs

Segmented Hashset Class

Useful for input or output buffer for use in parallel invoke operations where unique values are needed.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public class SegmentedHashSet<T> : IEnumerable<T>
{
    private readonly IntHs<T>[] _array;
    private readonly int        _size;
    private          int        _length;
    public SegmentedHashSet(int length, int size)
    {
        _array = new IntHs<T>[4096];
        for (var i = 0; i < length; ++i)
            _array[i] = new IntHs<T>(size);
        _length = length;
        _size   = size;
    }
    public IEnumerator<T> GetEnumerator()
    {
        throw new NotImplementedException();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item, int index)
    {
        if (index >= _length)
            for (var i = _length; i <= index; ++i)
            {
                _array[i] = new IntHs<T>(_size);
                _length++;
            }
        if (!ContainedInArray(item))
            _array[index].Add(item);
    }
    private bool ContainedInArray(T item)
    {
        for (var i = 0; i < _length; ++i)
            if (_array[i].Contains(item))
                return true;
        return false;
    }
    public T[] CombineToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _length; ++i)
            totalCount += _array[i].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _length; ++i)
        {
            var it = _array[i].ToArray();
            _array[i].Zero();
            for (var j = 0; j < it.Length; ++j)
                ta[ptr++] = it[j];
        }
        return ta;
    }
    [DebuggerDisplay("Count = {Count}")]
    internal class IntHs<T> : IEnumerable
    {
        private  Bucket[]             _buckets;
        internal IEqualityComparer<T> Comparer;
        public IntHs(int size) : this(size, null)
        {
        }
        public IntHs(int size, IEqualityComparer<T> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<T>.Default;
            Comparer = comparer;
            _buckets = new Bucket[size];
            Count    = 0;
        }
        public int Count
        {
            get;
            private set;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Zero()
        {
            _buckets = null;
            Count    = 0;
        }
        public bool Add(T item)
        {
            if (Count >= _buckets.Length)
                EnsureSize();
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var apos     = FindEntry(item, hashCode).APos;
            if (apos != -1)
                return false;
            var pos = hashCode % _buckets.Length;
            if (_buckets[pos] == null)
                _buckets[pos] = new Bucket();
            _buckets[pos].Add(item);
            Count++;
            return true;
        }
        public T[] ToArray()
        {
            var newArray = new T[Count];
            using (var en = GetEnumerator())
            {
                var ptr = 0;
                while (en.MoveNext())
                {
                    var value = en.Current;
                    if (value == null)
                        break;
                    newArray[ptr++] = value;
                }
                return newArray;
            }
        }
        private (int APos, int BPos) FindEntry(T item, int hashCode)
        {
            if (Count == 0)
                return (-1, -1);
            var aPos = hashCode % _buckets.Length;
            var bPos = 0;
            if (_buckets[aPos] == null)
            {
                _buckets[aPos] = new Bucket();
                return (-1, -1);
            }
            foreach (var i in _buckets[aPos].Values)
            {
                if (Equals(i, item))
                    return (aPos, bPos);
                bPos++;
            }
            return (-1, -1);
        }
        private void EnsureSize()
        {
            var cArray = ToArray();
            _buckets = new Bucket[_buckets.Length + _buckets.Length / 4 * 3];
            foreach (var i in cArray)
            {
                var hashCode = Comparer.GetHashCode(i) & int.MaxValue;
                var pos      = hashCode % _buckets.Length;
                if (_buckets[pos] == null)
                    _buckets[pos] = new Bucket();
                _buckets[pos].Add(i);
            }
        }
        public bool Contains(T item)
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            return FindEntry(item, hashCode).APos != -1;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return GetEnum();
        }
        public IEnumerator<T> GetEnum()
        {
            for (var i = 0; i < _buckets.Length; i++)
                if (_buckets[i] != null)
                    for (var j = 0; j < _buckets[i].Count; ++j)
                        yield return _buckets[i].Values[j];
        }
        internal class Bucket
        {
            public int Count;
            public T[] Values;
            public Bucket()
            {
                Values = new T[1];
                Count  = 0;
            }
            public void Add(T item)
            {
                if (Count >= Values.Length)
                    Array.Resize(ref Values, Values.Length + 1);
                Values[Count++] = item;
            }
        }
    }
}

JaggedArray.cs

Jagged Array Collection Class (No Copy Resize)

Updated: Jun-21,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
///     Uses a multidimensional array to create a growable array with out copy or re-allocation.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public struct JaggedArray<T> : IEnumerable<T>, IDisposable
{
    private const int   FirstDimensionMax = 4096;
    public const  int   ShiftCount        = 19;
    public const  int   Granularity       = 1 << ShiftCount;
    private       bool  _disposed;
    private       T[][] _array;
    public        int   Count;
    public        int   Length;
    public        int   NumberOfActiveArrays;
    public        bool  Allocated;
    public JaggedArray(int size)
    {
        if (size < Granularity)
            size = Granularity;
        try
        {
            NumberOfActiveArrays = (size + (Granularity - 1)) / Granularity;
            Length               = NumberOfActiveArrays       * Granularity;
            _array               = new T[FirstDimensionMax][];
            for (var i = 0; i < NumberOfActiveArrays; ++i)
                _array[i] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
        Count     = 0;
        _disposed = false;
        Allocated = true;
    }
    public T this[int index]
    {
        get
        {
            if (index >= Length)
                throw new Exception($"Getter: Index out of bounds, Index: '{index}' must be less than the Length: '{Length}'.");
            return _array[index >> ShiftCount][index & (Granularity - 1)];
        }
        set
        {
            if (index >= Length)
                ResizeArray();
            _array[index >> ShiftCount][index & (Granularity - 1)] = value;
            Count++;
        }
    }
    public void Dispose()
    {
        Dispose(true);
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T Item)
    {
        if (Count >= Length)
            ResizeArray();
        var x = Count >> ShiftCount;
        var y = Count & (Granularity - 1);
        _array[x][y] = Item;
        Count++;
    }
    private void ResizeArray()
    {
        try
        {
            _array[NumberOfActiveArrays] = new T[Granularity];
            NumberOfActiveArrays++;
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
    }
    public void Zero()
    {
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            _array[a] = Array.Empty<T>();
        Count = 0;
    }
    public void Clear()
    {
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Clear(_array[a], 0, Granularity);
        Count = 0;
    }
    public int IndexOf(T item)
    {
        var i = 0;
        for (; i < NumberOfActiveArrays; i++)
        {
            var pos = Array.IndexOf(_array[i], item, 0);
            if (pos != -1)
                return i * Granularity + pos;
        }
        return -1;
    }
    public JaggedArray<T> Copy(int newsize)
    {
        var temp = new JaggedArray<T>(newsize);
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(_array[a], temp._array[a], Granularity);
        temp.Count = Count;
        return temp;
    }
    public void FromArray(T[][] array)
    {
        NumberOfActiveArrays = array.GetUpperBound(0) + 1;
        Length               = NumberOfActiveArrays * Granularity;
        _array               = new T[NumberOfActiveArrays][];
        for (var i = 0; i < NumberOfActiveArrays; ++i)
            _array[i] = new T[Granularity];
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(array[a], _array[a], Granularity);
    }
    public T[][] ToRawArray()
    {
        var ta = new T[NumberOfActiveArrays][];
        for (var i = 0; i < NumberOfActiveArrays; ++i)
            ta[i] = new T[Granularity];
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(_array[a], ta[a], Granularity);
        return ta;
    }
    public T[] ToArray()
    {
        var newArray = new T[Count];
        using (var en = GetEnumerator())
        {
            var ptr = 0;
            while (en.MoveNext())
            {
                var value = en.Current;
                if (value == null)
                    break;
                newArray[ptr++] = value;
            }
            return newArray;
        }
    }
    private void Dispose(bool disposing)
    {
        if (!_disposed)
            if (disposing)
                _array = null;
        _disposed = true;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < Count; i++)
            yield return this[i];
    }
}

BucketHashSet3.cs

Single Array HashSet Class

Uses only a single array for tracking and storage.

Updated: July-11,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {Count}")]
public class BucketHashSet3<T> : IEnumerable
{
    private  Bucket[]             _buckets;
    internal IEqualityComparer<T> Comparer;
    private  int                  HiBucketCount;
    public BucketHashSet3() : this(1_000_000, 10, null)
    {
    }
    public BucketHashSet3(int sizeHint, int sizeHintBucket) : this(sizeHint, sizeHintBucket, null)
    {
    }
    public BucketHashSet3(int sizeHint, int sizeHintBucket, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer      = comparer;
        _buckets      = new Bucket[sizeHint];
        Count         = 0;
        HiBucketCount = 0;
        for (var i = 0; i < _buckets.Length; ++i)
            _buckets[i].Allocate(sizeHintBucket);
    }
    public int Count
    {
        get;
        private set;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Zero()
    {
        _buckets = null;
        Count    = 0;
    }
    public bool Add(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        var apos     = FindEntry(item, hashCode);
        if (apos != -1)
            return false;
        var pos = hashCode % _buckets.Length;
        _buckets[pos].Add(item);
        Count++;
        return true;
    }
    public T[] ToArray()
    {
        var newArray = new T[Count];
        using (var en = GetEnumerator())
        {
            var ptr = 0;
            while (en.MoveNext())
            {
                var value = en.Current;
                if (value == null)
                    break;
                newArray[ptr++] = value;
            }
            return newArray;
        }
    }
    private int FindEntry(T item, int hashCode)
    {
        if (Count == 0)
            return -1;
        var Pos = hashCode % _buckets.Length;
        if (_buckets[Pos].Count == 0)
            return -1;
        var cnt = _buckets[Pos].Count;
        if (cnt > HiBucketCount)
            HiBucketCount = cnt;
        if (HiBucketCount >= 100)
        {
            Resize();
            HiBucketCount = 0;
            return FindEntry(item, hashCode);
        }
        for (var i = 0; i < cnt; ++i)
        {
            var v = _buckets[Pos].Values[i];
            if (Comparer.Equals(v, item))
                return Pos;
        }
        return -1;
    }
    private void Resize()
    {
        var cArray  = ToArray();
        var newSize = _buckets.Length << 1;
        _buckets = new Bucket[newSize];
        for (var i = 0; i < newSize; ++i)
            _buckets[i].Allocate();
        foreach (var i in cArray)
            _buckets[BucketPosition(i)].Add(i);
    }
    private int BucketPosition(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        var pos      = hashCode % _buckets.Length;
        return pos;
    }
    public bool Contains(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        return FindEntry(item, hashCode) != -1;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < _buckets.Length; i++)
        for (var j = 0; j < _buckets[i].Count; ++j)
            yield return _buckets[i].Values[j];
    }
    internal struct Bucket
    {
        public int Count;
        public T[] Values;
        public void Add(T item)
        {
            if (Count >= Values.Length)
                Array.Resize(ref Values, Values.Length << 1);
            Values[Count++] = item;
        }
        public void Allocate(int size = 10)
        {
            Values = new T[size];
        }
    }
}

DigitsArray.cs

Support File, for use with BigIntX.cs

using System;
using System.Collections.Generic;
using System.Text;
public class DigitsArray
{
    public static readonly uint   AllBits;
    public static readonly uint   HiBitSet;
    public                 uint[] Data;
    static DigitsArray()
    {
        unchecked
        {
            AllBits  = ~(uint) 0;
            HiBitSet = (uint) 1 << (DataSizeBits - 1);
        }
    }
    public DigitsArray(int size)
    {
        Allocate(size, 0);
    }
    public DigitsArray(int size, int used)
    {
        Allocate(size, used);
    }
    public DigitsArray(uint[] copyFrom)
    {
        Allocate(copyFrom.Length);
        CopyFrom(copyFrom, 0, 0, copyFrom.Length);
        ResetDataUsed();
    }
    public DigitsArray(DigitsArray copyFrom)
    {
        Allocate(copyFrom.Count - 1, copyFrom.DataUsed);
        Array.Copy(copyFrom.Data, 0, Data, 0, copyFrom.Count);
    }
    public static int DataSizeOf   => sizeof(uint);
    public static int DataSizeBits => sizeof(uint) * 8;
    public uint this[int index]
    {
        get
        {
            if (index < Data.Length)
                return Data[index];
            return IsNegative ? AllBits : 0;
        }
        set => Data[index] = value;
    }
    public int DataUsed
    {
        get;
        set;
    }
    public int  Count      => Data.Length;
    public bool IsZero     => DataUsed == 0 || DataUsed == 1 && Data[0] == 0;
    public bool IsNegative => (Data[Data.Length - 1] & HiBitSet) == HiBitSet;
    public int Sign
    {
        get
        {
            if (Data[0] == 0)
                return 0;
            if (IsNegative)
                return -1;
            return 1;
        }
    }
    public void Allocate(int size)
    {
        Allocate(size, 0);
    }
    public void Allocate(int size, int used)
    {
        Data     = new uint[size + 1];
        DataUsed = used;
    }
    public void CopyFrom(uint[] source, int sourceOffset, int offset, int length)
    {
        Array.Copy(source, sourceOffset, Data, 0, length);
    }
    public void CopyTo(uint[] array, int offset, int length)
    {
        Array.Copy(Data, 0, array, offset, length);
    }
    public string GetDataAsString()
    {
        var result = new StringBuilder();
        foreach (var data in Data)
            result.Append(data + " ");
        return result.ToString();
    }
    public byte[] ToByteArray()
    {
        if (Data == null && Sign == 0)
            return new byte[1];
        uint[] dwords;
        byte   highByte;
        if (Data == null)
        {
            dwords   = new uint[1] {(uint) Sign};
            highByte = Sign < 0 ? byte.MaxValue : (byte) 0;
        }
        else if (Sign == -1)
        {
            dwords   = (uint[]) Data.Clone();
            dwords   = TwosComplement(dwords);
            highByte = byte.MaxValue;
        }
        else
        {
            dwords   = Data;
            highByte = 0;
        }
        var bytes   = new byte[checked(4 * dwords.Length)];
        var curByte = 0;
        for (var i = 0; i < dwords.Length; ++i)
        {
            var dword = dwords[i];
            for (var j = 0; j < 4; ++j)
            {
                bytes[curByte++] =   (byte) (dword & byte.MaxValue);
                dword            >>= 8;
            }
        }
        var msb = bytes.Length - 1;
        while (msb > 0 && bytes[msb] == highByte)
            --msb;
        var needExtraByte = (bytes[msb] & 128) != (highByte & 128);
        var timmedBytes   = new byte[msb + 1 + (needExtraByte ? 1 : 0)];
        Array.Copy(bytes, timmedBytes, msb + 1);
        if (needExtraByte)
            timmedBytes[timmedBytes.Length - 1] = highByte;
        return timmedBytes;
    }
    public uint[] ToUIn32Array()
    {
        var value = ToByteArray();
        var al    = value.Length >> 2;
        if (al << 2 != value.Length)
            al++;
        var arr = new uint[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public ulong[] ToUIn64Array()
    {
        var value = ToByteArray();
        var al    = value.Length >> 3;
        if (al << 3 != value.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    private static uint[] TwosComplement(uint[] d)
    {
        var  i = 0;
        uint v = 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
        {
            Array.Resize(ref d, d.Length + 1);
            d[d.Length - 1] = 1;
        }
        return d;
    }
    public void ResetDataUsed()
    {
        DataUsed = Data.Length;
        if (IsNegative)
        {
            while (DataUsed > 1 && Data[DataUsed - 1] == AllBits)
                --DataUsed;
            DataUsed++;
        }
        else
        {
            while (DataUsed > 1 && Data[DataUsed - 1] == 0)
                --DataUsed;
            if (DataUsed == 0)
                DataUsed = 1;
        }
    }
    public int ShiftRight(int shiftCount)
    {
        return ShiftRight(Data, shiftCount);
    }
    public static int ShiftRight(uint[] buffer, int shiftCount)
    {
        var shiftAmount = DataSizeBits;
        var invShift    = 0;
        var bufLen      = buffer.Length;
        while (bufLen > 1 && buffer[bufLen - 1] == 0)
            bufLen--;
        for (var count = shiftCount; count > 0; count -= shiftAmount)
        {
            if (count < shiftAmount)
            {
                shiftAmount = count;
                invShift    = DataSizeBits - shiftAmount;
            }
            ulong carry = 0;
            for (var i = bufLen - 1; i >= 0; i--)
            {
                var val = (ulong) buffer[i] >> shiftAmount;
                val       |= carry;
                carry     =  (ulong) buffer[i] << invShift;
                buffer[i] =  (uint) val;
            }
        }
        while (bufLen > 1 && buffer[bufLen - 1] == 0)
            bufLen--;
        return bufLen;
    }
    public int ShiftLeft(int shiftCount)
    {
        return ShiftLeft(Data, shiftCount);
    }
    public static int ShiftLeft(uint[] buffer, int shiftCount)
    {
        var shiftAmount = DataSizeBits;
        var bufLen      = buffer.Length;
        while (bufLen > 1 && buffer[bufLen - 1] == 0)
            bufLen--;
        for (var count = shiftCount; count > 0; count -= shiftAmount)
        {
            if (count < shiftAmount)
                shiftAmount = count;
            ulong carry = 0;
            for (var i = 0; i < bufLen; i++)
            {
                var val = (ulong) buffer[i] << shiftAmount;
                val       |= carry;
                buffer[i] =  (uint) (val & AllBits);
                carry     =  val >> DataSizeBits;
            }
            if (carry != 0)
            {
                if (bufLen + 1 <= buffer.Length)
                {
                    buffer[bufLen] = (uint) carry;
                    bufLen++;
                    carry = 0;
                }
                else
                {
                    throw new OverflowException();
                }
            }
        }
        return bufLen;
    }
    public int ShiftLeftWithoutOverflow(int shiftCount)
    {
        if (shiftCount == 0) return Data.Length;
        var temporary   = new List<uint>(Data);
        var shiftAmount = DataSizeBits;
        for (var count = shiftCount; count > 0; count -= shiftAmount)
        {
            if (count < shiftAmount)
                shiftAmount = count;
            ulong carry = 0;
            for (var i = 0; i < temporary.Count; i++)
            {
                var val = (ulong) temporary[i] << shiftAmount;
                val          |= carry;
                temporary[i] =  (uint) (val & AllBits);
                carry        =  val >> DataSizeBits;
            }
            if (carry != 0)
            {
                var lastNum = (uint) carry;
                if (IsNegative)
                {
                    var byteCount = (int) Math.Floor(Math.Log(carry, 2));
                    lastNum = (0xffffffff << byteCount) | (uint) carry;
                }
                temporary.Add(lastNum);
            }
        }
        Data = new uint[temporary.Count];
        temporary.CopyTo(Data);
        return Data.Length;
    }
}

BigIntX.cs

Variable Bit Width Big Unsigned or Signed Integer 32,64,128,256,512,1024,204,4096 Bit. (Experimental)

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Text;
[Serializable]
[TypeConverter(typeof(BigIntXConverter))]
[DebuggerDisplay("{DDisplay}")]
public struct BigIntX : IComparable<BigIntX>, IComparable, IEquatable<BigIntX>, IConvertible, IFormattable
{
    internal DigitsArray _digitsArray;
    public BigIntX(byte number) : this((ulong)number)
    {
    }
    public BigIntX(sbyte number) : this((long)number)
    {
    }
    public BigIntX(bool number) : this((ulong)(number ? 1 : 0))
    {
    }
    public BigIntX(char number) : this((ulong)number)
    {
    }
    public BigIntX(short number) : this((long)number)
    {
    }
    public BigIntX(ushort number) : this((ulong)number)
    {
    }
    public BigIntX(int number) : this((long)number)
    {
    }
    public BigIntX(uint number) : this((ulong)number)
    {
    }
    public BigIntX(BigDecimal number)
    {
        var array    = number.UnscaledValue.ToByteArray();
        var length   = array.Length;
        var offset   = 0;
        var estSize  = length / 4;
        var leftOver = length & 3;
        if (leftOver != 0)
            ++estSize;
        _digitsArray = new DigitsArray(estSize + 1, 0);
        for (int i = offset + length - 1, j = 0; i - offset >= 3; i -= 4, j++)
        {
            _digitsArray[j] = (uint)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]);
            _digitsArray.DataUsed++;
        }
        uint accumulator = 0;
        for (var i = leftOver; i > 0; i--)
        {
            uint digit = array[offset + leftOver - i];
            digit       =  digit << ((i - 1) * 8);
            accumulator |= digit;
        }
        _digitsArray[_digitsArray.DataUsed] = accumulator;
        _digitsArray.ResetDataUsed();
    }
    public BigIntX(BigInteger number)
    {
        var array    = number.ToByteArray().Invert();
        var length   = array.Length;
        var offset   = 0;
        var estSize  = length / 4;
        var leftOver = length & 3;
        if (leftOver != 0)
            ++estSize;
        _digitsArray = new DigitsArray(estSize + 1, 0);
        for (int i = offset + length - 1, j = 0; i - offset >= 3; i -= 4, j++)
        {
            _digitsArray[j] = (uint)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]);
            _digitsArray.DataUsed++;
        }
        uint accumulator = 0;
        for (var i = leftOver; i > 0; i--)
        {
            uint digit = array[offset + leftOver - i];
            digit       =  digit << ((i - 1) * 8);
            accumulator |= digit;
        }
        _digitsArray[_digitsArray.DataUsed] = accumulator;
        _digitsArray.ResetDataUsed();
    }
    public BigIntX(decimal number)
    {
        var bits   = decimal.GetBits(decimal.Truncate(number));
        var length = 3;
        while (length > 0 && bits[length - 1] == 0)
            --length;
        var IsNegative = (bits[3] & int.MinValue) != 0;
        _digitsArray = new DigitsArray(3, 0);
        if (length == 0)
        {
            ConstructFrom(new byte[] { 0 }, 0, 1);
            return;
        }
        if (length == 1)
        {
            if (!IsNegative)
            {
                _digitsArray.Data[0] = (uint)bits[0];
            }
            else
            {
                _digitsArray.Data[0] = DigitsArray.AllBits - (uint)bits[0] + 1;
                _digitsArray.Data[1] = DigitsArray.AllBits                 - (uint)bits[1];
                _digitsArray.Data[2] = DigitsArray.AllBits                 - (uint)bits[2];
                _digitsArray.Data[3] = DigitsArray.AllBits;
            }
            _digitsArray.ResetDataUsed();
            return;
        }
        if (length == 2)
        {
            if (!IsNegative)
            {
                _digitsArray.Data[0] = (uint)bits[0];
                _digitsArray.Data[1] = (uint)bits[1];
            }
            else
            {
                _digitsArray.Data[0] = DigitsArray.AllBits - (uint)bits[0] + 1;
                _digitsArray.Data[1] = DigitsArray.AllBits                 - (uint)bits[1];
                _digitsArray.Data[2] = DigitsArray.AllBits                 - (uint)bits[2];
                _digitsArray.Data[3] = DigitsArray.AllBits;
            }
            _digitsArray.ResetDataUsed();
            return;
        }
        if (length == 3)
        {
            if (!IsNegative)
            {
                _digitsArray.Data[0] = (uint)bits[0];
                _digitsArray.Data[1] = (uint)bits[1];
                _digitsArray.Data[2] = (uint)bits[2];
            }
            else
            {
                _digitsArray.Data[0] = DigitsArray.AllBits - (uint)bits[0] + 1;
                _digitsArray.Data[1] = DigitsArray.AllBits                 - (uint)bits[1];
                _digitsArray.Data[2] = DigitsArray.AllBits                 - (uint)bits[2];
                _digitsArray.Data[3] = DigitsArray.AllBits;
            }
            _digitsArray.ResetDataUsed();
        }
    }
    public BigIntX(double value) : this((decimal)value)
    {
    }
    public BigIntX(float value) : this((decimal)value)
    {
    }
    public BigIntX(Guid value) : this(value.ToByteArray())
    {
    }
    public BigIntX(long number)
    {
        _digitsArray = new DigitsArray(8 / DigitsArray.DataSizeOf + 1, 0);
        while (number != 0 && _digitsArray.DataUsed < _digitsArray.Count)
        {
            _digitsArray[_digitsArray.DataUsed] =   (uint)(number & DigitsArray.AllBits);
            number                              >>= DigitsArray.DataSizeBits;
            _digitsArray.DataUsed++;
        }
        _digitsArray.ResetDataUsed();
    }
    public BigIntX(ulong number)
    {
        _digitsArray = new DigitsArray(8 / DigitsArray.DataSizeOf + 1, 0);
        while (number != 0 && _digitsArray.DataUsed < _digitsArray.Count)
        {
            _digitsArray[_digitsArray.DataUsed] =   (uint)(number & DigitsArray.AllBits);
            number                              >>= DigitsArray.DataSizeBits;
            _digitsArray.DataUsed++;
        }
        _digitsArray.ResetDataUsed();
    }
    public BigIntX(byte[] array) : this(array, 0, array.Length)
    {
    }
    public BigIntX(byte[] array, int length) : this(array, 0, length)
    {
    }
    public BigIntX(byte[] array, int offset, int length)
    {
        var estSize  = length / 4;
        var leftOver = length & 3;
        if (leftOver != 0)
            ++estSize;
        _digitsArray = new DigitsArray(estSize + 1, 0);
        for (int i = offset + length - 1, j = 0; i - offset >= 3; i -= 4, j++)
        {
            _digitsArray[j] = (uint)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]);
            _digitsArray.DataUsed++;
        }
        uint accumulator = 0;
        for (var i = leftOver; i > 0; i--)
        {
            uint digit = array[offset + leftOver - i];
            digit       =  digit << ((i - 1) * 8);
            accumulator |= digit;
        }
        _digitsArray[_digitsArray.DataUsed] = accumulator;
        _digitsArray.ResetDataUsed();
    }
    public BigIntX(string digits) : this(digits, 10)
    {
    }
    public BigIntX(string digits, int radix)
    {
        if (digits == null)
            throw new ArgumentNullException("digits");
        var multiplier = new BigIntX(1);
        var result     = new BigIntX();
        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
                throw new ArgumentOutOfRangeException("digits");
            if (d >= radix)
                throw new ArgumentOutOfRangeException("digits");
            result     += multiplier * d;
            multiplier *= radix;
        }
        if (digits[0] == '-')
            result = -result;
        _digitsArray = result._digitsArray;
    }
    private BigIntX(DigitsArray digits)
    {
        digits.ResetDataUsed();
        _digitsArray = digits;
    }
    public BigIntX(xIntX value) : this(value.ToByteArray().Invert(), 0, value.ToByteArray().Length)
    {
    }
    internal BigIntX(uint[] rgu)
    {
        _digitsArray      = new DigitsArray(1, 1);
        _digitsArray.Data = rgu;
        _digitsArray.ResetDataUsed();
    }
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public bool IsNegative => _digitsArray.IsNegative;
    public bool IsZero     => _digitsArray.IsZero;
    public int  Sign       => _digitsArray.Sign;
    public bool IsPowerOfTwo
    {
        get
        {
            if (Sign != 1)
                return false;
            var index = Length(_digitsArray.Data) - 1;
            if (((int)_digitsArray.Data[index] & ((int)_digitsArray.Data[index] - 1)) != 0)
                return false;
            while (--index >= 0)
                if (_digitsArray.Data[index] != 0U)
                    return false;
            return true;
        }
    }
    public bool IsOne  => this     == 1;
    public bool IsEven => this % 2 == 0;
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, (BigIntX)obj);
    }
    public int CompareTo(BigIntX value)
    {
        return Compare(this, value);
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return bool.Parse(ToString());
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return byte.Parse(ToString());
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return char.Parse(ToString());
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        return DateTime.Parse(ToString());
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return decimal.Parse(ToString());
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return double.Parse(ToString());
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return short.Parse(ToString());
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        return ushort.Parse(ToString());
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return int.Parse(ToString());
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        return uint.Parse(ToString());
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return long.Parse(ToString());
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        return ulong.Parse(ToString());
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return sbyte.Parse(ToString());
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return float.Parse(ToString());
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool Equals(BigIntX obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        var c = obj;
        if (_digitsArray.DataUsed != c._digitsArray.DataUsed)
            return false;
        for (var idx = 0; idx < _digitsArray.DataUsed; idx++)
            if (_digitsArray[idx] != c._digitsArray[idx])
                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')
                if (int.TryParse(format.Substring(1).Trim(), out var min))
                    return ToHexString();
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString(10);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = bool.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = byte.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = char.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = decimal.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = double.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = short.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = int.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = long.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = sbyte.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = float.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = ushort.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = uint.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = ulong.Parse(ToString());
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    private void ConstructFrom(byte[] array, int offset, int length)
    {
        if (array == null)
            throw new ArgumentNullException("Array is null");
        if (offset > array.Length || length > array.Length)
            throw new ArgumentOutOfRangeException("Offset exceeds length");
        if (length > array.Length || offset + length > array.Length)
            throw new ArgumentOutOfRangeException("Length exceeds array length");
        var estSize  = length / 4;
        var leftOver = length & 3;
        if (leftOver != 0)
            ++estSize;
        _digitsArray = new DigitsArray(estSize + 1, 0);
        for (int i = offset + length - 1, j = 0; i - offset >= 3; i -= 4, j++)
        {
            _digitsArray[j] = (uint)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]);
            _digitsArray.DataUsed++;
        }
        uint accumulator = 0;
        for (var i = leftOver; i > 0; i--)
        {
            uint digit = array[offset + leftOver - i];
            digit       =  digit << ((i - 1) * 8);
            accumulator |= digit;
        }
        _digitsArray[_digitsArray.DataUsed] = accumulator;
        _digitsArray.ResetDataUsed();
    }
    private void Construct(string digits, int radix)
    {
        if (digits == null)
            throw new ArgumentNullException("digits");
        var multiplier = new BigIntX(1);
        var result     = new BigIntX();
        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
                throw new ArgumentOutOfRangeException("digits");
            if (d >= radix)
                throw new ArgumentOutOfRangeException("digits");
            result     += multiplier * d;
            multiplier *= radix;
        }
        if (digits[0] == '-')
            result = -result;
        _digitsArray = result._digitsArray;
    }
    public static bool TryParseNum(string digits, int radix, out BigIntX result)
    {
        result = new BigIntX();
        if (digits == null)
            return false;
        var multiplier = new BigIntX(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 BigIntX Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static BigIntX Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static BigIntX Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static BigIntX 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 BigIntX result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out BigIntX result)
    {
        result = new BigIntX();
        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 implicit operator BigIntX(BigDecimal value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(BigInteger value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(xIntX value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(bool value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(byte value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(char value)
    {
        return new BigIntX(value);
    }
    public static explicit operator BigIntX(decimal value)
    {
        return new BigIntX(value);
    }
    public static explicit operator BigIntX(double value)
    {
        return new BigIntX(value);
    }
    public static explicit operator BigIntX(float value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(short value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(ushort value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(sbyte value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(long value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(ulong value)
    {
        return new BigIntX(value);
    }
    public static implicit operator BigIntX(int value)
    {
        return new BigIntX(value);
    }
    public static explicit operator byte(BigIntX value)
    {
        return checked((byte)(int)value);
    }
    public static explicit operator sbyte(BigIntX value)
    {
        return checked((sbyte)(int)value);
    }
    public static implicit operator BigIntX(uint value)
    {
        return new BigIntX((ulong)value);
    }
    public static explicit operator short(BigIntX value)
    {
        return checked((short)(int)value);
    }
    public static explicit operator ushort(BigIntX value)
    {
        return checked((ushort)(int)value);
    }
    public static explicit operator BigInteger(BigIntX value)
    {
        return new BigInteger(value.ToByteArray());
    }
    public static explicit operator xIntX(BigIntX value)
    {
        return new xIntX(value.ToByteArray());
    }
    public static explicit operator int(BigIntX value)
    {
        if (value.IsZero)
            return 0;
        if (value.Sign > 0)
            return checked((int)value._digitsArray.Data[0]);
        if (value > int.MaxValue)
            throw new OverflowException("int overflow.");
        return -(int)value._digitsArray.Data[0];
    }
    public static explicit operator uint(BigIntX value)
    {
        return value._digitsArray.Data[0];
    }
    public static explicit operator long(BigIntX value)
    {
        if (value > long.MaxValue)
            throw new OverflowException("long overflow.");
        var uu = value._digitsArray.Data.Length - 1 <= 1 ? value._digitsArray.Data[0] : ((ulong)value._digitsArray.Data[1] << 32) | value._digitsArray.Data[0];
        var ll = value.Sign                         > 0 ? (long)uu : -(long)uu;
        if (ll > 0L && value.Sign > 0 || ll < 0L && value.Sign < 0)
            return ll;
        throw new OverflowException("long overflow.");
    }
    public static explicit operator ulong(BigIntX value)
    {
        if (value > ulong.MaxValue)
            throw new OverflowException("ulong overflow.");
        if (value._digitsArray.Data.Length - 1 > 1)
            return ((ulong)value._digitsArray.Data[1] << 32) | value._digitsArray.Data[0];
        return value._digitsArray.Data[0];
    }
    public static decimal ToDecimal(BigIntX value)
    {
        var len = value._digitsArray.Data.Length - 1;
        if (len > 3)
            throw new OverflowException("Decimal overflow.");
        ;
        var lo  = 0;
        var mid = 0;
        var hi  = 0;
        if (len > 2)
            hi = (int)value._digitsArray.Data[2];
        if (len > 1)
            mid = (int)value._digitsArray.Data[1];
        if (len > 0)
            lo = (int)value._digitsArray.Data[0];
        return new decimal(lo, mid, hi, value.Sign < 0, 0);
    }
    public static explicit operator decimal(BigIntX value)
    {
        var len = value._digitsArray.Data.Length - 1;
        if (len > 3)
            throw new OverflowException("Decimal overflow.");
        ;
        var lo  = 0;
        var mid = 0;
        var hi  = 0;
        if (len > 2)
            hi = (int)value._digitsArray.Data[2];
        if (len > 1)
            mid = (int)value._digitsArray.Data[1];
        if (len > 0)
            lo = (int)value._digitsArray.Data[0];
        return new decimal(lo, mid, hi, value.Sign < 0, 0);
    }
    public static BigIntX operator +(BigIntX left, BigIntX right)
    {
        var  size  = Math.Max(left._digitsArray.DataUsed, right._digitsArray.DataUsed);
        var  da    = new DigitsArray(size + 1);
        long carry = 0;
        for (var i = 0; i < da.Count; i++)
        {
            var sum = left._digitsArray[i] + (long)right._digitsArray[i] + carry;
            carry = sum >> DigitsArray.DataSizeBits;
            da[i] = (uint)(sum & DigitsArray.AllBits);
        }
        return new BigIntX(da);
    }
    public static BigIntX Add(BigIntX left, BigIntX right)
    {
        return left + right;
    }
    public static BigIntX operator ++(BigIntX left)
    {
        return left + 1;
    }
    public static BigIntX Increment(BigIntX left)
    {
        return left + 1;
    }
    public static BigIntX operator -(BigIntX left, BigIntX right)
    {
        var  size  = Math.Max(left._digitsArray.DataUsed, right._digitsArray.DataUsed) + 1;
        var  da    = new DigitsArray(size);
        long carry = 0;
        for (var i = 0; i < da.Count; i++)
        {
            var diff = left._digitsArray[i] - (long)right._digitsArray[i] - carry;
            da[i] = (uint)(diff & DigitsArray.AllBits);
            da.DataUsed++;
            carry = diff < 0 ? 1 : 0;
        }
        return new BigIntX(da);
    }
    public static BigIntX Subtract(BigIntX left, BigIntX right)
    {
        return left - right;
    }
    public static BigIntX operator --(BigIntX left)
    {
        return left - 1;
    }
    public static BigIntX Decrement(BigIntX left)
    {
        return left - 1;
    }
    public static BigIntX operator -(BigIntX left)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (left.IsZero)
            return new BigIntX(0);
        var da = new DigitsArray(left._digitsArray.DataUsed + 1, left._digitsArray.DataUsed + 1);
        for (var i = 0; i < da.Count; i++)
            da[i] = ~left._digitsArray[i];
        var carry = true;
        var index = 0;
        while (carry && index < da.Count)
        {
            var val = (long)da[index] + 1;
            da[index] = (uint)(val & DigitsArray.AllBits);
            carry     = val >> DigitsArray.DataSizeBits > 0;
            index++;
        }
        return new BigIntX(da);
    }
    public BigIntX Negate()
    {
        return -this;
    }
    public static BigIntX Abs(BigIntX left)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (left.IsNegative)
            return -left;
        return left;
    }
    public static BigIntX operator *(BigIntX left, BigIntX right)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        var leftSideNeg  = left.IsNegative;
        var rightSideNeg = right.IsNegative;
        left  = Abs(left);
        right = Abs(right);
        var da = new DigitsArray(left._digitsArray.DataUsed + right._digitsArray.DataUsed);
        da.DataUsed = da.Count;
        for (var i = 0; i < left._digitsArray.DataUsed; i++)
        {
            ulong carry = 0;
            for (int j = 0, k = i; j < right._digitsArray.DataUsed; j++, k++)
            {
                var val = left._digitsArray[i] * (ulong)right._digitsArray[j] + da[k] + carry;
                da[k] = (uint)(val & DigitsArray.AllBits);
                carry = val >> DigitsArray.DataSizeBits;
            }
            if (carry != 0)
                da[i + right._digitsArray.DataUsed] = (uint)carry;
        }
        var result = new BigIntX(da);
        return leftSideNeg != rightSideNeg ? -result : result;
    }
    public static BigIntX Multiply(BigIntX left, BigIntX right)
    {
        return left * right;
    }
    public static BigIntX operator /(BigIntX left, BigIntX right)
    {
        if (left == null)
            throw new ArgumentNullException("left");
        if (right == null)
            throw new ArgumentNullException("right");
        if (right.IsZero)
            throw new DivideByZeroException();
        var divisorNeg  = right.IsNegative;
        var dividendNeg = left.IsNegative;
        left  = Abs(left);
        right = Abs(right);
        if (left < right)
            return new BigIntX(0);
        Divide(left, right, out var quotient, out var remainder);
        return dividendNeg != divisorNeg ? -quotient : quotient;
    }
    public static BigIntX Divide(BigIntX left, BigIntX right)
    {
        return left / right;
    }
    private static void Divide(BigIntX left, BigIntX right, out BigIntX quotient, out BigIntX remainder)
    {
        if (left.IsZero)
        {
            quotient  = new BigIntX();
            remainder = new BigIntX();
            return;
        }
        if (right._digitsArray.DataUsed == 1)
            SingleDivide(left, right, out quotient, out remainder);
        else
            MultiDivide(left, right, out quotient, out remainder);
    }
    private static void MultiDivide(BigIntX left, BigIntX right, out BigIntX quotient, out BigIntX remainder)
    {
        if (right.IsZero)
            throw new DivideByZeroException();
        var val = right._digitsArray[right._digitsArray.DataUsed - 1];
        var d   = 0;
        for (var mask = DigitsArray.HiBitSet; mask != 0 && (val & mask) == 0; mask >>= 1)
            d++;
        var remainderLen = left._digitsArray.DataUsed + 1;
        var remainderDat = new uint[remainderLen];
        left._digitsArray.CopyTo(remainderDat, 0, left._digitsArray.DataUsed);
        DigitsArray.ShiftLeft(remainderDat, d);
        right = right << d;
        ulong firstDivisor  = right._digitsArray[right._digitsArray.DataUsed - 1];
        ulong secondDivisor = right._digitsArray.DataUsed < 2 ? 0 : right._digitsArray[right._digitsArray.DataUsed - 2];
        var   divisorLen    = right._digitsArray.DataUsed + 1;
        var   dividendPart  = new DigitsArray(divisorLen, divisorLen);
        var   result        = new uint[left._digitsArray.Count + 1];
        var   resultPos     = 0;
        var   carryBit      = (ulong)0x1 << DigitsArray.DataSizeBits;
        for (int j = remainderLen - right._digitsArray.DataUsed, pos = remainderLen - 1; j > 0; j--, pos--)
        {
            var dividend = ((ulong)remainderDat[pos] << DigitsArray.DataSizeBits) + remainderDat[pos - 1];
            var qHat     = dividend / firstDivisor;
            var rHat     = dividend % firstDivisor;
            while (pos >= 2)
            {
                if (qHat == carryBit || qHat * secondDivisor > (rHat << DigitsArray.DataSizeBits) + remainderDat[pos - 2])
                {
                    qHat--;
                    rHat += firstDivisor;
                    if (rHat < carryBit)
                        continue;
                }
                break;
            }
            for (var h = 0; h < divisorLen; h++)
                dividendPart[divisorLen - h - 1] = remainderDat[pos - h];
            var dTemp = new BigIntX(dividendPart);
            var rTemp = right * (long)qHat;
            while (rTemp > dTemp)
            {
                qHat--;
                rTemp -= right;
            }
            rTemp = dTemp - rTemp;
            for (var h = 0; h < divisorLen; h++)
                remainderDat[pos - h] = rTemp._digitsArray[right._digitsArray.DataUsed - h];
            result[resultPos++] = (uint)qHat;
        }
        Array.Reverse(result, 0, resultPos);
        quotient = new BigIntX(new DigitsArray(result));
        var n   = DigitsArray.ShiftRight(remainderDat, d);
        var rDA = new DigitsArray(n, n);
        rDA.CopyFrom(remainderDat, 0, 0, rDA.DataUsed);
        remainder = new BigIntX(rDA);
    }
    private static void SingleDivide(BigIntX left, BigIntX right, out BigIntX quotient, out BigIntX remainder)
    {
        if (right.IsZero)
            throw new DivideByZeroException();
        var remainderDigits = new DigitsArray(left._digitsArray);
        remainderDigits.ResetDataUsed();
        var pos      = remainderDigits.DataUsed - 1;
        var divisor  = (ulong)right._digitsArray[0];
        var dividend = (ulong)remainderDigits[pos];
        var result   = new uint[left._digitsArray.Count];
        left._digitsArray.CopyTo(result, 0, result.Length);
        var resultPos = 0;
        if (dividend >= divisor)
        {
            result[resultPos++]  = (uint)(dividend / divisor);
            remainderDigits[pos] = (uint)(dividend % divisor);
        }
        pos--;
        while (pos >= 0)
        {
            dividend                 = ((ulong)remainderDigits[pos + 1] << DigitsArray.DataSizeBits) + remainderDigits[pos];
            result[resultPos++]      = (uint)(dividend / divisor);
            remainderDigits[pos + 1] = 0;
            remainderDigits[pos--]   = (uint)(dividend % divisor);
        }
        remainder = new BigIntX(remainderDigits);
        var quotientDigits = new DigitsArray(resultPos + 1, resultPos);
        var j              = 0;
        for (var i = quotientDigits.DataUsed - 1; i >= 0; i--, j++)
            quotientDigits[j] = result[i];
        quotient = new BigIntX(quotientDigits);
    }
    public static BigIntX operator %(BigIntX left, BigIntX right)
    {
        if (left == null)
            throw new ArgumentNullException("left");
        if (right == null)
            throw new ArgumentNullException("right");
        if (right.IsZero)
            throw new DivideByZeroException();
        BigIntX quotient;
        BigIntX remainder;
        var     dividendNeg = left.IsNegative;
        left  = Abs(left);
        right = Abs(right);
        if (left < right)
            return left;
        Divide(left, right, out quotient, out remainder);
        return dividendNeg ? -remainder : remainder;
    }
    public static BigIntX Modulus(BigIntX left, BigIntX right)
    {
        return left % right;
    }
    public BigIntX Pow(BigIntX power)
    {
        return Pow(this, power);
    }
    public static BigIntX operator &(BigIntX left, BigIntX right)
    {
        var len = Math.Max(left._digitsArray.DataUsed, right._digitsArray.DataUsed);
        var da  = new DigitsArray(len, len);
        for (var idx = 0; idx < len; idx++)
            da[idx] = left._digitsArray[idx] & right._digitsArray[idx];
        return new BigIntX(da);
    }
    public static BigIntX BitwiseAnd(BigIntX left, BigIntX right)
    {
        return left & right;
    }
    public static BigIntX operator |(BigIntX left, BigIntX right)
    {
        var len = Math.Max(left._digitsArray.DataUsed, right._digitsArray.DataUsed);
        var da  = new DigitsArray(len, len);
        for (var idx = 0; idx < len; idx++)
            da[idx] = left._digitsArray[idx] | right._digitsArray[idx];
        return new BigIntX(da);
    }
    public static BigIntX BitwiseOr(BigIntX left, BigIntX right)
    {
        return left | right;
    }
    public static BigIntX operator ^(BigIntX left, BigIntX right)
    {
        var len = Math.Max(left._digitsArray.DataUsed, right._digitsArray.DataUsed);
        var da  = new DigitsArray(len, len);
        for (var idx = 0; idx < len; idx++)
            da[idx] = left._digitsArray[idx] ^ right._digitsArray[idx];
        return new BigIntX(da);
    }
    public static BigIntX Xor(BigIntX left, BigIntX right)
    {
        return left ^ right;
    }
    public static BigIntX operator ~(BigIntX left)
    {
        var da = new DigitsArray(left._digitsArray.Count);
        for (var idx = 0; idx < da.Count; idx++)
            da[idx] = ~left._digitsArray[idx];
        return new BigIntX(da);
    }
    public static BigIntX OnesComplement(BigIntX left)
    {
        return ~left;
    }
    public static BigIntX operator <<(BigIntX left, int shiftCount)
    {
        if (left == null)
            throw new ArgumentNullException("left");
        var da = new DigitsArray(left._digitsArray);
        da.DataUsed = da.ShiftLeftWithoutOverflow(shiftCount);
        return new BigIntX(da);
    }
    public static BigIntX LeftShift(BigIntX left, int shiftCount)
    {
        return left << shiftCount;
    }
    public static BigIntX operator >> (BigIntX left, int shiftCount)
    {
        if (left == null)
            throw new ArgumentNullException("left");
        var da = new DigitsArray(left._digitsArray);
        da.DataUsed = da.ShiftRight(shiftCount);
        if (left.IsNegative)
        {
            for (var i = da.Count - 1; i >= da.DataUsed; i--)
                da[i] = DigitsArray.AllBits;
            var mask = DigitsArray.HiBitSet;
            for (var i = 0; i < DigitsArray.DataSizeBits; i++)
            {
                if ((da[da.DataUsed - 1] & mask) == DigitsArray.HiBitSet)
                    break;
                da[da.DataUsed - 1] |=  mask;
                mask                >>= 1;
            }
            da.DataUsed = da.Count;
        }
        return new BigIntX(da);
    }
    public static BigIntX RightShift(BigIntX left, int shiftCount)
    {
        if (left == null)
            throw new ArgumentNullException("left");
        return left >> shiftCount;
    }
    public static int Compare(BigIntX left, BigIntX 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 bool operator ==(BigIntX left, BigIntX right)
    {
        if (ReferenceEquals(left, right))
            return true;
        if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
            return false;
        if (left.IsNegative != right.IsNegative)
            return false;
        return left.Equals(right);
    }
    public static bool operator !=(BigIntX left, BigIntX right)
    {
        return !(left == right);
    }
    public static bool operator >(BigIntX left, BigIntX right)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        if (left.IsNegative != right.IsNegative)
            return right.IsNegative;
        if (left._digitsArray.DataUsed != right._digitsArray.DataUsed)
            return left._digitsArray.DataUsed > right._digitsArray.DataUsed;
        for (var idx = left._digitsArray.DataUsed - 1; idx >= 0; idx--)
            if (left._digitsArray[idx] != right._digitsArray[idx])
                return left._digitsArray[idx] > right._digitsArray[idx];
        return false;
    }
    public static bool operator <(BigIntX left, BigIntX right)
    {
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        if (left.IsNegative != right.IsNegative)
            return left.IsNegative;
        if (left._digitsArray.DataUsed != right._digitsArray.DataUsed)
            return left._digitsArray.DataUsed < right._digitsArray.DataUsed;
        for (var idx = left._digitsArray.DataUsed - 1; idx >= 0; idx--)
            if (left._digitsArray[idx] != right._digitsArray[idx])
                return left._digitsArray[idx] < right._digitsArray[idx];
        return false;
    }
    public static bool operator >=(BigIntX left, BigIntX right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(BigIntX left, BigIntX right)
    {
        return Compare(left, right) <= 0;
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        var c = (BigIntX)obj;
        if (_digitsArray.DataUsed != c._digitsArray.DataUsed)
            return false;
        for (var idx = 0; idx < _digitsArray.DataUsed; idx++)
            if (_digitsArray[idx] != c._digitsArray[idx])
                return false;
        return true;
    }
    public override int GetHashCode()
    {
        var hash = 0x811c9dc5;
        for (var i = 0; i < _digitsArray.Data.Length; i++)
        {
            hash =  ((hash << 13) | (hash >> 19)) ^ _digitsArray.Data[i];
            hash *= 0x1000193;
        }
        return (int)hash;
    }
    public string GetDataAsString()
    {
        return _digitsArray.GetDataAsString();
    }
    public override string ToString()
    {
        return ToString(10);
    }
    public byte[] ToByteArray()
    {
        return _digitsArray.ToByteArray();
    }
    public uint[] ToUIn32Array()
    {
        return _digitsArray.ToUIn32Array();
    }
    public ulong[] ToUIn64Array()
    {
        return _digitsArray.ToUIn64Array();
    }
    public string ToString(int radix)
    {
        if (radix < 2 || radix > 36)
            throw new ArgumentOutOfRangeException("radix");
        if (IsZero)
            return "0";
        var a        = this;
        var negative = a.IsNegative;
        a = Abs(this);
        BigIntX      quotient;
        BigIntX      remainder;
        var          biRadix = new BigIntX(radix);
        const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz";
        var          al      = new ArrayList();
        while (a._digitsArray.DataUsed > 1 || a._digitsArray.DataUsed == 1 && a._digitsArray[0] != 0)
        {
            Divide(a, biRadix, out quotient, out remainder);
            al.Insert(0, charSet[(int)remainder._digitsArray[0]]);
            a = quotient;
        }
        var result = new string((char[])al.ToArray(typeof(char)));
        if (radix == 10 && negative)
            return "-" + result;
        return result;
    }
    public string ToHexString()
    {
        var sb = new StringBuilder();
        sb.AppendFormat("{0:X}", _digitsArray[_digitsArray.DataUsed - 1]);
        var f = "{0:X" + 2 * DigitsArray.DataSizeOf + "}";
        for (var i = _digitsArray.DataUsed - 2; i >= 0; i--)
            sb.AppendFormat(f, _digitsArray[i]);
        return sb.ToString();
    }
    public string ToBinaryString()
    {
        var bytes  = ToByteArray();
        var index  = bytes.Length - 1;
        var base2  = new StringBuilder(bytes.Length * 8);
        var binary = Convert.ToString(bytes[index], 2);
        if (binary[0] != '0' && Sign == 1) base2.Append('0');
        base2.Append(binary);
        for (index--; index >= 0; index--)
            base2.Append(Convert.ToString(bytes[index], 2).PadLeft(8, '0'));
        return base2.ToString();
    }
    public string ToOctalString()
    {
        var bytes         = ToByteArray();
        var index         = bytes.Length - 1;
        var base8         = new StringBuilder((bytes.Length / 3 + 1) * 8);
        var rem           = bytes.Length % 3;
        if (rem == 0) rem = 3;
        var base0         = 0;
        while (rem != 0)
        {
            base0 <<= 8;
            base0 +=  bytes[index--];
            rem--;
        }
        var octal = Convert.ToString(base0, 8);
        if (octal[0] != '0' && Sign == 1) base8.Append('0');
        base8.Append(octal);
        while (index >= 0)
        {
            base0 = (bytes[index] << 16) + (bytes[index - 1] << 8) + bytes[index - 2];
            base8.Append(Convert.ToString(base0, 8).PadLeft(8, '0'));
            index -= 3;
        }
        return base8.ToString();
    }
    public static int ToInt16(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return short.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static uint ToUInt16(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return ushort.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static int ToInt32(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return int.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static uint ToUInt32(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return uint.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static long ToInt64(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return long.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static ulong ToUInt64(BigIntX value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        return ulong.Parse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture);
    }
    public static BigIntX Pow(BigIntX value, BigIntX exponent)
    {
        if (value == null)
            throw new ArgumentNullException("Value cannot be null");
        if (exponent == null)
            throw new ArgumentNullException("Exponent cannot be null");
        if (exponent < 0)
            throw new ArgumentOutOfRangeException("Exponent", "Exponent cannot be negative");
        BigIntX result = 1;
        while (exponent != 0)
        {
            if ((exponent & 1) != 0)
                result *= value;
            exponent >>= 1;
            value    *=  value;
        }
        return result;
    }
    public static BigIntX ModPow(BigIntX n, BigIntX e, BigInteger m)
    {
        var n1 = n;
        var e1 = e;
        var c  = 0;
        if (e1 == 0)
            return 1;
        if (e1 == 1)
            return n1 % m;
        if (e1 == 2)
            return n1 * n1 % m;
        BigIntX r;
        n1 %= m;
        r  =  1;
        if ((e1 & 1) == 1)
            r = n1;
        while (e1 > 1)
        {
            c++;
            e1 >>= 1;
            n1 =   n1 * n1 % m;
            if ((e1 & 1) == 1)
                r = r * n1 % m;
        }
        return r;
    }
    public static BigIntX Sqrt(BigIntX n)
    {
        var q = (BigIntX)1 << ((int)Log(n, 2) >> 1);
        var m = (BigIntX)0;
        while (Abs(q - m) >= 1)
        {
            m = q;
            q = (m + n / m) >> 1;
        }
        return q;
    }
    public static double Log(BigIntX value, double baseValue)
    {
        Array.Resize(ref value._digitsArray.Data, value._digitsArray.DataUsed);
        var c          = 0.0;
        var d          = 0.5;
        var dataLength = Length(value._digitsArray.Data);
        var topBits    = BitLengthOfUInt(value._digitsArray.Data[dataLength - 1]);
        var bitLength  = (dataLength - 1) * 32 + topBits;
        var bit        = (uint)(1 << (topBits - 1));
        for (var index = dataLength - 1; index >= 0; --index)
        {
            for (; bit != 0U; bit >>= 1)
            {
                if (((int)value._digitsArray.Data[index] & (int)bit) != 0)
                    c += d;
                d *= 0.5;
            }
            bit = 2147483648U;
        }
        return (Math.Log(c) + 0.693147180559945 * bitLength) / Math.Log(baseValue);
    }
    private static int BitLengthOfUInt(uint x)
    {
        var numBits = 0;
        while (x > 0)
        {
            x >>= 1;
            numBits++;
        }
        return numBits;
    }
    private static int Length(uint[] rgu)
    {
        var length = rgu.Length;
        return rgu[length - 1] != 0U ? length : length - 1;
    }
    public static List<BigIntX> GetFactors(BigIntX n)
    {
        var Factors = new List<BigIntX>();
        var s       = Sqrt(n);
        var a       = (BigIntX)3;
        while (a < s)
        {
            if (n % a == 0)
            {
                Factors.Add(a);
                if (a * a != n)
                    Factors.Add(n / a);
            }
            a += 2;
        }
        return Factors;
    }
    public static BigIntX Gcd(BigIntX a, BigIntX b)
    {
        while (b > 0)
        {
            var r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    public static BigIntX Lcm(BigIntX a, BigIntX b)
    {
        return a * b / a.Gcd(b);
    }
    public static int GetBitWidth(BigIntX value)
    {
        var bw = 1;
        var v  = value;
        while ((v >>= 1) > 0)
            bw++;
        if (bw < 8)
            bw = 8;
        return bw;
    }
    public static BigIntX GetMaxValueBitWidth(int bitLength)
    {
        return ((BigIntX)1 << bitLength) - 1;
    }
    public static BigIntX GetMaxValue(BigIntX value)
    {
        var bitLength = GetBitWidth(value);
        return ((BigIntX)1 << bitLength) - 1;
    }
    public static BigIntX Min(BigIntX left, BigIntX right)
    {
        if (left.CompareTo(right) <= 0)
            return left;
        return right;
    }
    public static BigIntX Max(BigIntX left, BigIntX right)
    {
        if (left.CompareTo(right) < 0)
            return right;
        return left;
    }
    public static double Log10(BigIntX value)
    {
        return Log(value, 10.0);
    }
    public static double LogN(BigIntX value)
    {
        return Log(value, 2.0);
    }
    private class BigIntXConverter : 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 BigIntX();
        }
        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);
        }
    }
}