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

Leave a Reply

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