Last active
June 15, 2021 18:21
-
-
Save mjs3339/3ea79ceb538d8d8b04d7beddfa633c0c to your computer and use it in GitHub Desktop.
Adjustable Bit Width Big Unsigned or Signed Integer 32,64,128,256,512,1024,2048…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Diagnostics; | |
using System.Globalization; | |
using System.Numerics; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
[Serializable] | |
[StructLayout(LayoutKind.Sequential, Pack = 1)] | |
[TypeConverter(typeof(xIntXConverter))] | |
[DebuggerDisplay("{DDisplay}")] | |
public struct xIntX : IComparable<xIntX>, IComparable, IEquatable<xIntX>, IConvertible, IFormattable | |
{ | |
private const int DefaultDataBitWidth = 1024; | |
private const int DataSize = sizeof(uint); | |
private const uint AllBits = ~(uint)0; | |
private const int DataSizeBits = sizeof(uint) * 8; | |
private const uint HiNeg = (uint)1 << (DataSizeBits - 1); | |
private static int _dataBitWidth; | |
private static int DataLength; | |
private static bool _unsigned; | |
public uint[] Data; | |
public xIntX(xIntX value, int bitLength = 0, bool unsigned = false) | |
{ | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
_unsigned = unsigned; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
value.Data.CopyTo(Data, 0); | |
} | |
public xIntX(string value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
if (!TryParse(value, out var result)) | |
throw new Exception("TryParse Failed."); | |
Data = new uint[DataLength]; | |
result.Data.CopyTo(Data, 0); | |
} | |
public xIntX(byte value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[0] = value; | |
} | |
public xIntX(bool value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[0] = (uint)(value ? 1 : 0); | |
} | |
public xIntX(char value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[0] = value; | |
} | |
public xIntX(BigDecimal value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
var ba = value.WholePart.ToByteArray(); | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
var len = ba.Length / DataSize; | |
var lim = Math.Min(len, DataLength); | |
Data = new uint[lim]; | |
for (var i = 0; i < lim; i++) | |
Data[i] = BitConverter.ToUInt32(ba, i * DataSize); | |
} | |
public xIntX(BigRational value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
var v1 = value.Numerator.ToByteArray(); | |
DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
var byteCount = v1.Length; | |
var isNegative = _unsigned == false && byteCount > 0 && (v1[byteCount - 1] & 0x80) == 0x80; | |
var unalignedBytes = byteCount % DataSize; | |
var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1); | |
Data = new uint[Math.Max(dwordCount, DataLength)]; | |
if (byteCount == 0) | |
return; | |
int curDword, curByte, byteInDword; | |
curByte = 3; | |
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) | |
{ | |
byteInDword = 0; | |
while (byteInDword < DataSize) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= v1[curByte]; | |
curByte--; | |
byteInDword++; | |
} | |
curByte += 8; | |
} | |
if (unalignedBytes != 0) | |
{ | |
if (isNegative) | |
Data[dwordCount - 1] = 0xffffffff; | |
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= v1[curByte]; | |
} | |
} | |
} | |
public xIntX(decimal value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
if (value < 0 && !_unsigned) | |
{ | |
var n = -new xIntX(-value, DataBitWidth, _unsigned); | |
n.Data.CopyTo(Data, 0); | |
return; | |
} | |
var bits = decimal.GetBits(value); | |
Data[2] = (uint)bits[2]; | |
Data[1] = (uint)bits[1]; | |
Data[0] = (uint)bits[0]; | |
} | |
public xIntX(double value, int bitLength = 0, bool unsigned = false) : this((decimal)value, bitLength, unsigned) | |
{ | |
} | |
public xIntX(float value, int bitLength = 0, bool unsigned = false) : this((decimal)value, bitLength, unsigned) | |
{ | |
} | |
public xIntX(short value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
if (value < 0 && !_unsigned) | |
{ | |
var n = -new xIntX(-(value + 1), DataBitWidth, _unsigned) - 1; | |
n.Data.CopyTo(Data, 0); | |
return; | |
} | |
Data[0] = (uint)value; | |
} | |
public xIntX(int value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
if (value < 0 && !_unsigned) | |
{ | |
var n = -new xIntX(-(value + 1), DataBitWidth, _unsigned) - 1; | |
n.Data.CopyTo(Data, 0); | |
return; | |
} | |
Data[0] = (uint)value; | |
} | |
public xIntX(long value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
if (value < 0 && !_unsigned) | |
{ | |
var n = -new xIntX(-(value + 1), DataBitWidth, _unsigned) - 1; | |
n.Data.CopyTo(Data, 0); | |
return; | |
} | |
Data[1] = (uint)((value >> 32) & 0xffffffff); | |
Data[0] = (uint)(value & 0xffffffff); | |
} | |
public xIntX(sbyte value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
if (value < 0 && !_unsigned) | |
{ | |
var n = -new xIntX(-(value + 1), DataBitWidth, _unsigned) - 1; | |
n.Data.CopyTo(Data, 0); | |
return; | |
} | |
Data[0] = (uint)value; | |
} | |
public xIntX(ushort value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[0] = value; | |
} | |
public xIntX(uint value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[0] = value; | |
} | |
public xIntX(ulong value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
Data[1] = (uint)((value >> 32) & 0xffffffff); | |
Data[0] = (uint)(value & 0xffffffff); | |
} | |
public xIntX(BigInteger value, int bitLength = 0, bool unsigned = false) : this(value.ToByteArray(), bitLength, unsigned) | |
{ | |
} | |
public xIntX(Guid value, int bitLength = 0, bool unsigned = false) : this(value.ToByteArray(), bitLength, unsigned) | |
{ | |
} | |
public xIntX(byte[] value, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
var minSize = value.Length / DataSize; | |
if (value == null) | |
throw new ArgumentNullException("value"); | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
var byteCount = value.Length; | |
var isNegative = _unsigned == false && byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80; | |
var unalignedBytes = byteCount % DataSize; | |
var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1); | |
Data = new uint[Math.Max(dwordCount, DataLength)]; | |
if (byteCount == 0) | |
return; | |
int curDword, curByte, byteInDword; | |
curByte = 3; | |
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) | |
{ | |
byteInDword = 0; | |
while (byteInDword < DataSize) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= value[curByte]; | |
curByte--; | |
byteInDword++; | |
} | |
curByte += 8; | |
} | |
if (unalignedBytes != 0) | |
{ | |
if (isNegative) | |
Data[dwordCount - 1] = 0xffffffff; | |
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= value[curByte]; | |
} | |
} | |
} | |
public xIntX(int sign, uint[] array, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (array == null) | |
throw new Exception("Array cannot be null."); | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
Data = new uint[DataLength]; | |
var ba = new byte[DataSize]; | |
for (var i = 0; i < Math.Min(DataLength, array.Length); i++) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize); | |
Data[i] = BitConverter.ToUInt32(ba, 0); | |
} | |
if (!_unsigned) | |
{ | |
if (sign < 0) | |
Data[DataLength - 1] |= HiNeg; | |
else | |
Data[DataLength - 1] &= ~HiNeg; | |
} | |
} | |
public xIntX(uint[] array, int bitLength = 0, bool unsigned = false) | |
{ | |
_unsigned = unsigned; | |
if (array == null) | |
throw new Exception("Array cannot be null."); | |
if (bitLength == 0) | |
DataBitWidth = DefaultDataBitWidth; | |
else DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
if (array.Length != DataLength) | |
Array.Resize(ref array, DataLength); | |
Data = new uint[DataLength]; | |
var ba = new byte[DataSize]; | |
for (var i = 0; i < Data.Length; i++) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize); | |
Data[i] = BitConverter.ToUInt32(ba, 0); | |
} | |
} | |
public bool Unsigned | |
{ | |
get => _unsigned; | |
set => _unsigned = value; | |
} | |
private static int DataBitWidth | |
{ | |
get => _dataBitWidth; | |
set | |
{ | |
_dataBitWidth = value; | |
if (_dataBitWidth < 32) | |
_dataBitWidth = 32; | |
} | |
} | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
private string DDisplay => ToString(); | |
public xIntX MaxValue | |
{ | |
get | |
{ | |
var r = new xIntX(0, DataBitWidth, _unsigned); | |
for (var i = 0; i < r.Data.Length; ++i) | |
r.Data[i] = uint.MaxValue; | |
r.Data[r.Data.Length - 1] = int.MaxValue; | |
return r; | |
} | |
} | |
public int BitWidth | |
{ | |
get | |
{ | |
xIntX bw = 1; | |
var v = new xIntX(this, DataBitWidth, _unsigned); | |
while ((v >>= 1) > 0) | |
bw++; | |
if (bw < 8) | |
bw = 8; | |
while (bw % 8 != 0) | |
bw++; | |
return (int)bw; | |
} | |
} | |
public float MaxDecimalPlaces => DataBitWidth / 64f * 20f; | |
public int DecimalPlaces | |
{ | |
get | |
{ | |
var a = new xIntX(this, DataBitWidth, _unsigned); | |
var dPlaces = 0; | |
if (a.Sign == 0) | |
return 1; | |
if (a.Sign < 0) | |
try | |
{ | |
a = -a; | |
} | |
catch (Exception ex) | |
{ | |
return 0; | |
} | |
var biRadix = new xIntX(10, DataBitWidth, _unsigned); | |
while (a > 0) | |
try | |
{ | |
Divide(a, biRadix, out var remainder, out var quotient); | |
a = quotient; | |
dPlaces++; | |
} | |
catch (Exception ex) | |
{ | |
break; | |
} | |
return dPlaces; | |
} | |
} | |
public int Sign | |
{ | |
get | |
{ | |
if (_unsigned) | |
return 1; | |
var allZero = true; | |
var ba = Data; | |
for (var i = 0; i < ba.Length; i++) | |
if (ba[i] != 0) | |
{ | |
allZero = false; | |
break; | |
} | |
if (allZero) | |
return 0; | |
return (Data[Data.Length - 1] & HiNeg) == 0 ? 1 : -1; | |
} | |
} | |
public bool IsOne => this == 1; | |
public bool IsEven => (this & 1) == 0; | |
public bool IsNegative => Sign < 0; | |
public bool IsZero | |
{ | |
get | |
{ | |
for (var i = 0; i < Data.Length; i++) | |
if (Data[i] != 0) | |
return false; | |
return true; | |
} | |
} | |
public int DataUsed | |
{ | |
get | |
{ | |
var DataUsed = Data.Length; | |
if (!IsNegative) | |
{ | |
while (DataUsed > 1 && Data[DataUsed - 1] == 0) | |
--DataUsed; | |
if (DataUsed == 0) | |
DataUsed = 1; | |
} | |
return DataUsed; | |
} | |
} | |
int IComparable.CompareTo(object obj) | |
{ | |
return Compare(this, obj); | |
} | |
public int CompareTo(xIntX value) | |
{ | |
return Compare(this, value); | |
} | |
TypeCode IConvertible.GetTypeCode() | |
{ | |
return TypeCode.Object; | |
} | |
bool IConvertible.ToBoolean(IFormatProvider provider) | |
{ | |
return (bool)this; | |
} | |
byte IConvertible.ToByte(IFormatProvider provider) | |
{ | |
return (byte)this; | |
} | |
char IConvertible.ToChar(IFormatProvider provider) | |
{ | |
return (char)this; | |
} | |
DateTime IConvertible.ToDateTime(IFormatProvider provider) | |
{ | |
throw new InvalidCastException(); | |
} | |
decimal IConvertible.ToDecimal(IFormatProvider provider) | |
{ | |
return (decimal)this; | |
} | |
double IConvertible.ToDouble(IFormatProvider provider) | |
{ | |
return (double)this; | |
} | |
short IConvertible.ToInt16(IFormatProvider provider) | |
{ | |
return (short)this; | |
} | |
int IConvertible.ToInt32(IFormatProvider provider) | |
{ | |
return (int)this; | |
} | |
long IConvertible.ToInt64(IFormatProvider provider) | |
{ | |
return (long)this; | |
} | |
sbyte IConvertible.ToSByte(IFormatProvider provider) | |
{ | |
return (sbyte)this; | |
} | |
float IConvertible.ToSingle(IFormatProvider provider) | |
{ | |
return (float)this; | |
} | |
string IConvertible.ToString(IFormatProvider provider) | |
{ | |
return ToString(null, provider); | |
} | |
public object ToType(Type conversionType, IFormatProvider provider) | |
{ | |
object value; | |
if (TryConvert(conversionType, provider, out value)) | |
return value; | |
throw new InvalidCastException(); | |
} | |
ushort IConvertible.ToUInt16(IFormatProvider provider) | |
{ | |
if (Data[1] != 0) | |
throw new OverflowException(); | |
return Convert.ToUInt16(Data[0]); | |
} | |
uint IConvertible.ToUInt32(IFormatProvider provider) | |
{ | |
if (Data[1] != 0) | |
throw new OverflowException(); | |
return Convert.ToUInt32(Data[0]); | |
} | |
ulong IConvertible.ToUInt64(IFormatProvider provider) | |
{ | |
if (Data[1] != 0) | |
return ((ulong)Data[1] << 32) | Data[0]; | |
return Data[0]; | |
} | |
public bool Equals(xIntX obj) | |
{ | |
if (ReferenceEquals(obj, null)) | |
return false; | |
if (ReferenceEquals(this, obj)) | |
return true; | |
if (Data.Length != obj.Data.Length) | |
return false; | |
if (Sign != obj.Sign) | |
return false; | |
for (var i = 0; i < Data.Length; i++) | |
if (Data[i] != obj.Data[i]) | |
return false; | |
return true; | |
} | |
public string ToString(string format, IFormatProvider formatProvider) | |
{ | |
if (formatProvider == null) | |
formatProvider = CultureInfo.CurrentCulture; | |
if (!string.IsNullOrEmpty(format)) | |
{ | |
var ch = format[0]; | |
if (ch == 'x' || ch == 'X') | |
{ | |
int.TryParse(format.Substring(1).Trim(), out var min); | |
return ToHexString(ch == 'X'); | |
} | |
if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd') | |
throw new NotSupportedException("Not supported format: " + format); | |
} | |
return ToString((NumberFormatInfo)formatProvider.GetFormat(typeof(NumberFormatInfo)), 10); | |
} | |
private static byte[] ToByteArray(ulong[] value) | |
{ | |
var ba = new byte[value.Length << 3]; | |
Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3); | |
return ba; | |
} | |
private static byte[] ToByteArray(uint[] value) | |
{ | |
var ba = new byte[value.Length << 2]; | |
Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2); | |
return ba; | |
} | |
public override int GetHashCode() | |
{ | |
static uint CombineHash(uint u1, uint u2) | |
{ | |
return ((u1 << 7) | (u1 >> 25)) ^ u2; | |
} | |
var s = Sign; | |
var i = Data.Length; | |
while (--i >= 0) | |
s = (int)CombineHash((uint)s, Data[i]); | |
return s; | |
} | |
public static byte[] GetBytesInt(xIntX value) | |
{ | |
var b = value.Sign.GetBytes(); | |
var tb = b.Add(value.Data.GetBytes()); | |
return tb; | |
} | |
public override bool Equals(object obj) | |
{ | |
return base.Equals(obj); | |
} | |
public override string ToString() | |
{ | |
return ToString(null, null); | |
} | |
public string ToString(string format) | |
{ | |
return ToString(format, null); | |
} | |
public string ToHexString(bool caps) | |
{ | |
var bytes = ToByteArray().Invert(); | |
var sb = new StringBuilder(); | |
var x = caps ? "X" : "x"; | |
foreach (var b in bytes) | |
{ | |
var hex = b.ToString($"{x}2"); | |
sb.Append(hex); | |
} | |
return sb.ToString(); | |
} | |
private string ToString(NumberFormatInfo info, int radix) | |
{ | |
if (radix < 2 || radix > 36) | |
throw new ArgumentOutOfRangeException("radix"); | |
if (Sign == 0) | |
return "0"; | |
var negative = Sign < 0; | |
var a = new xIntX(this, DataBitWidth, _unsigned); | |
if (negative) | |
try | |
{ | |
a = -a; | |
} | |
catch (Exception ex) | |
{ | |
} | |
var biRadix = new xIntX(radix, DataBitWidth, _unsigned); | |
const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
var al = new ArrayList(); | |
while (a > 0) | |
try | |
{ | |
Divide(a, biRadix, out var remainder, out var quotient); | |
al.Insert(0, charSet[(int)remainder.Data[0]]); | |
a = quotient; | |
} | |
catch (Exception ex) | |
{ | |
break; | |
} | |
var result = new string((char[])al.ToArray(typeof(char))); | |
if (radix == 10 && negative) | |
return "-" + result; | |
return result; | |
} | |
public static xIntX Abs(xIntX value) | |
{ | |
if (ReferenceEquals(value, null)) | |
throw new ArgumentNullException("value"); | |
if (value.Sign < 0) | |
return -value; | |
return value; | |
} | |
public bool TryConvert(Type conversionType, IFormatProvider provider, out object value) | |
{ | |
if (conversionType == typeof(bool)) | |
{ | |
value = (bool)this; | |
return true; | |
} | |
if (conversionType == typeof(byte)) | |
{ | |
value = (byte)this; | |
return true; | |
} | |
if (conversionType == typeof(char)) | |
{ | |
value = (char)this; | |
return true; | |
} | |
if (conversionType == typeof(decimal)) | |
{ | |
value = (decimal)this; | |
return true; | |
} | |
if (conversionType == typeof(double)) | |
{ | |
value = (double)this; | |
return true; | |
} | |
if (conversionType == typeof(short)) | |
{ | |
value = (short)this; | |
return true; | |
} | |
if (conversionType == typeof(int)) | |
{ | |
value = (int)this; | |
return true; | |
} | |
if (conversionType == typeof(long)) | |
{ | |
value = (long)this; | |
return true; | |
} | |
if (conversionType == typeof(sbyte)) | |
{ | |
value = (sbyte)this; | |
return true; | |
} | |
if (conversionType == typeof(float)) | |
{ | |
value = (float)this; | |
return true; | |
} | |
if (conversionType == typeof(string)) | |
{ | |
value = ToString(null, provider); | |
return true; | |
} | |
if (conversionType == typeof(ushort)) | |
{ | |
value = (ushort)this; | |
return true; | |
} | |
if (conversionType == typeof(uint)) | |
{ | |
value = (uint)this; | |
return true; | |
} | |
if (conversionType == typeof(ulong)) | |
{ | |
value = (ulong)this; | |
return true; | |
} | |
if (conversionType == typeof(byte[])) | |
{ | |
value = ToByteArray(); | |
return true; | |
} | |
if (conversionType == typeof(Guid)) | |
{ | |
value = new Guid(ToByteArray()); | |
return true; | |
} | |
value = null; | |
return false; | |
} | |
public static xIntX Parse(string value) | |
{ | |
return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); | |
} | |
public static xIntX Parse(string value, NumberStyles style) | |
{ | |
return Parse(value, style, NumberFormatInfo.CurrentInfo); | |
} | |
public static xIntX Parse(string value, IFormatProvider provider) | |
{ | |
return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); | |
} | |
public static xIntX 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 xIntX result) | |
{ | |
return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); | |
} | |
public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out xIntX result) | |
{ | |
result = 0; | |
if (string.IsNullOrEmpty(value)) | |
return false; | |
if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase)) | |
{ | |
style |= NumberStyles.AllowHexSpecifier; | |
value = value.Substring(1); | |
} | |
else | |
{ | |
if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) | |
{ | |
style |= NumberStyles.AllowHexSpecifier; | |
value = value.Substring(2); | |
} | |
} | |
if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier) | |
return TryParseNum(value, 16, out result); | |
return TryParseNum(value, 10, out result); | |
} | |
public static bool TryParseNum(string digits, int radix, out xIntX result) | |
{ | |
result = new xIntX(0, DataBitWidth, _unsigned); | |
if (digits == null) | |
return false; | |
var multiplier = new xIntX(1, DataBitWidth * 2, _unsigned); | |
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 != 48) | |
{ | |
var a = 1; | |
} | |
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 (multiplier.DataUsed > DataLength) | |
throw new Exception($"Data overflow in Multiplier {new StackFrame(1, true).GetFileLineNumber()} "); | |
} | |
if (digits[0] == '-' && !_unsigned) | |
result = -result; | |
return true; | |
} | |
public static int Compare(xIntX left, object right) | |
{ | |
if (right is xIntX) | |
return Compare(left, (xIntX)right); | |
if (right is bool) | |
return Compare(left, new xIntX((bool)right, DataBitWidth, _unsigned)); | |
if (right is byte) | |
return Compare(left, new xIntX((byte)right, DataBitWidth, _unsigned)); | |
if (right is char) | |
return Compare(left, new xIntX((char)right, DataBitWidth, _unsigned)); | |
if (right is decimal) | |
return Compare(left, new xIntX((decimal)right, DataBitWidth, _unsigned)); | |
if (right is double) | |
return Compare(left, new xIntX((double)right, DataBitWidth, _unsigned)); | |
if (right is short) | |
return Compare(left, new xIntX((short)right, DataBitWidth, _unsigned)); | |
if (right is int) | |
return Compare(left, new xIntX((int)right, DataBitWidth, _unsigned)); | |
if (right is long) | |
return Compare(left, new xIntX((long)right, DataBitWidth, _unsigned)); | |
if (right is sbyte) | |
return Compare(left, new xIntX((sbyte)right, DataBitWidth, _unsigned)); | |
if (right is float) | |
return Compare(left, new xIntX((float)right, DataBitWidth, _unsigned)); | |
if (right is ushort) | |
return Compare(left, new xIntX((ushort)right, DataBitWidth, _unsigned)); | |
if (right is uint) | |
return Compare(left, new xIntX((uint)right, DataBitWidth, _unsigned)); | |
if (right is ulong) | |
return Compare(left, new xIntX((ulong)right, DataBitWidth, _unsigned)); | |
var bytes = right as byte[]; | |
if (bytes != null) | |
return Compare(left, new xIntX(bytes, DataBitWidth, _unsigned)); | |
if (right is Guid) | |
return Compare(left, new xIntX((Guid)right, DataBitWidth, _unsigned)); | |
throw new ArgumentException(); | |
} | |
public static int Compare(xIntX left, xIntX right) | |
{ | |
if (ReferenceEquals(left, right)) | |
return 0; | |
if (left.Sign >= 0 && right.Sign < 0) | |
return 1; | |
if (left.Sign < 0 && right.Sign >= 0) | |
return -1; | |
if (left.Data.Length != right.Data.Length) | |
return -1; | |
for (var i = left.Data.Length - 1; i > 0; i--) | |
if (left.Data[i] != right.Data[i]) | |
return left.Data[i].CompareTo(right.Data[i]); | |
return left.Data[0].CompareTo(right.Data[0]); | |
} | |
public static implicit operator xIntX(bool value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(byte value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(char value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static explicit operator xIntX(decimal value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static explicit operator xIntX(double value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(short value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(int value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(long value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(sbyte value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static explicit operator xIntX(float value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(ushort value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(uint value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(ulong value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(BigInteger value) | |
{ | |
if (DataBitWidth == 0) | |
DataBitWidth = value.GetBitWidth(); | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(BigRational value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static implicit operator xIntX(BigDecimal value) | |
{ | |
return new xIntX(value, DataBitWidth, _unsigned); | |
} | |
public static explicit operator bool(xIntX value) | |
{ | |
return (byte)value.Data[0] != 0; | |
} | |
public static explicit operator byte(xIntX value) | |
{ | |
return (byte)value.Data[0]; | |
} | |
public static explicit operator char(xIntX value) | |
{ | |
return (char)(ushort)value.Data[0]; | |
} | |
public static explicit operator decimal(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
if (value.Data.Length == 1) | |
return new decimal((int)value.Data[0], 0, 0, value.Sign < 0, 0); | |
if (value.Data.Length == 2) | |
return new decimal((int)value.Data[0], (int)value.Data[1], 0, value.Sign < 0, 0); | |
if (value.Data.Length == 3) | |
return new decimal((int)value.Data[0], (int)value.Data[1], (int)value.Data[2], value.Sign < 0, 0); | |
throw new ArgumentException("Value length exceeds decimal length."); | |
} | |
public static explicit operator double(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
var nfi = CultureInfo.InvariantCulture.NumberFormat; | |
if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d)) | |
throw new OverflowException(); | |
return d; | |
} | |
public static explicit operator float(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
var nfi = CultureInfo.InvariantCulture.NumberFormat; | |
if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f)) | |
throw new OverflowException(); | |
return f; | |
} | |
public static explicit operator short(xIntX value) | |
{ | |
if (value.Data[0] > 0x8000) | |
throw new OverflowException(); | |
if (value.Data[0] == 0x8000 && value.Sign > 0) | |
throw new OverflowException(); | |
return (short)((int)value.Data[0] * value.Sign); | |
} | |
public static explicit operator int(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
return (int)value.Data[0] * value.Sign; | |
} | |
public static explicit operator long(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
if (value.Data[0] > int.MaxValue) | |
throw new OverflowException(); | |
if (value.Data.Length > 1) | |
if (value.Data[1] != 0) | |
return (long)(((ulong)value.Data[1] << 32) | value.Data[0]) * value.Sign; | |
return value.Data[0] * value.Sign; | |
} | |
public static explicit operator uint(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
return value.Data[0]; | |
} | |
public static explicit operator ushort(xIntX value) | |
{ | |
if (value.Sign == 0) | |
return 0; | |
return (ushort)value.Data[0]; | |
} | |
public static explicit operator ulong(xIntX value) | |
{ | |
if (value.Data.Length > 1) | |
if (value.Data[1] != 0) | |
return ((ulong)value.Data[1] << 32) | value.Data[0]; | |
return value.Data[0]; | |
} | |
public static explicit operator BigInteger(xIntX value) | |
{ | |
return new BigInteger(value.ToByteArray()); | |
} | |
public static explicit operator BigDecimal(xIntX value) | |
{ | |
return new xIntX(value.ToByteArray()); | |
} | |
public static explicit operator BigRational(xIntX value) | |
{ | |
return new BigRational(new BigInteger(value.ToByteArray())); | |
} | |
public static bool operator >(xIntX left, xIntX right) | |
{ | |
return left.CompareTo(right) > 0; | |
} | |
public static bool operator <(xIntX left, xIntX right) | |
{ | |
return Compare(left, right) < 0; | |
} | |
public static bool operator >=(xIntX left, xIntX right) | |
{ | |
return Compare(left, right) >= 0; | |
} | |
public static bool operator <=(xIntX left, xIntX right) | |
{ | |
return Compare(left, right) <= 0; | |
} | |
public static bool operator !=(xIntX left, xIntX right) | |
{ | |
return !left.Equals(right); | |
} | |
public static bool operator ==(xIntX left, xIntX right) | |
{ | |
return left.Equals(right); | |
} | |
public static xIntX operator +(xIntX value) | |
{ | |
return value; | |
} | |
public static xIntX operator ~(xIntX value) | |
{ | |
var da = new uint[DataLength]; | |
for (var idx = 0; idx < DataLength; idx++) | |
da[idx] = ~value.Data[idx]; | |
return new xIntX(da, DataBitWidth); | |
} | |
public static xIntX operator -(xIntX value) | |
{ | |
if (ReferenceEquals(value, null)) | |
throw new ArgumentNullException("value"); | |
if (value.IsZero) | |
return 0; | |
var da = new uint[DataLength]; | |
for (var i = 0; i < da.Length; i++) | |
da[i] = ~value.Data[i]; | |
var carry = true; | |
var index = 0; | |
while (carry && index < da.Length) | |
{ | |
var val = (long)da[index] + 1; | |
da[index] = (uint)(val & AllBits); | |
carry = val >> DataSizeBits > 0; | |
index++; | |
} | |
return new xIntX(da, DataBitWidth); | |
} | |
public static xIntX operator ++(xIntX value) | |
{ | |
return value + 1; | |
} | |
public static xIntX operator --(xIntX value) | |
{ | |
return value - 1; | |
} | |
public static xIntX Negate(xIntX value) | |
{ | |
var ldata = (uint[])value.Data.Clone(); | |
for (var i = 0; i < value.Data.Length; i++) | |
ldata[i] = ~value.Data[i]; | |
return new xIntX(value.Sign, ldata, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator +(xIntX left, xIntX right) | |
{ | |
if (right.IsZero) | |
return left; | |
if (left.IsZero) | |
return right; | |
var dl = Math.Max(left.Data.Length, right.Data.Length); | |
var lim = Math.Min(left.Data.Length, right.Data.Length); | |
var result = new uint[dl]; | |
long carry = 0; | |
for (var i = 0; i < dl && i < lim; i++) | |
{ | |
var sum = left.Data[i] + (long)right.Data[i] + carry; | |
carry = sum >> 32; | |
result[i] = (uint)(sum & 0xFFFFFFFF); | |
} | |
if (carry != 0) | |
{ | |
var idx = 0; | |
while (idx < result.Length - 1) | |
{ | |
if (result[idx] == 0) | |
break; | |
idx++; | |
} | |
result[idx] = (uint)carry; | |
} | |
return new xIntX(left.Sign * right.Sign, result, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator -(xIntX left, xIntX right) | |
{ | |
if (right.IsZero) | |
return left; | |
if (left.IsZero) | |
return -right; | |
var size = Math.Max(left.Data.Length, right.Data.Length) + 1; | |
var da = new uint[size]; | |
long carry = 0; | |
for (var i = 0; i < DataLength && i < left.Data.Length && i < right.Data.Length; i++) | |
{ | |
var diff = left.Data[i] - (long)right.Data[i] - carry; | |
da[i] = (uint)(diff & AllBits); | |
carry = diff < 0 ? 1 : 0; | |
} | |
return new xIntX(da, DataBitWidth); | |
} | |
public static xIntX Add(xIntX left, xIntX right) | |
{ | |
return left + right; | |
} | |
public static xIntX Subtract(xIntX left, xIntX right) | |
{ | |
return left - right; | |
} | |
public static xIntX Divide(xIntX dividend, xIntX divisor) | |
{ | |
if (divisor == 0) | |
throw new DivideByZeroException(); | |
return DivRem(dividend, divisor, out var integer); | |
} | |
public static void Divide(xIntX dividend, xIntX divisor, out xIntX remainder, out xIntX quotient) | |
{ | |
if (divisor == 0) | |
throw new DivideByZeroException(); | |
DivRem(dividend.Data, divisor.Data, out var quo, out var rem); | |
remainder = new xIntX(1, rem, DataBitWidth, _unsigned); | |
quotient = new xIntX(dividend.Sign * divisor.Sign, quo, DataBitWidth, _unsigned); | |
} | |
public static xIntX DivRem(xIntX dividend, xIntX divisor, out xIntX remainder) | |
{ | |
if (divisor == 0) | |
throw new DivideByZeroException(); | |
DivRem(dividend.Data, divisor.Data, out var quotient, out var rem); | |
remainder = new xIntX(1, rem, DataBitWidth, _unsigned); | |
return new xIntX(dividend.Sign * divisor.Sign, quotient, DataBitWidth, _unsigned); | |
} | |
private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder) | |
{ | |
const ulong hiBit = 0x100000000; | |
var divisorLen = GetLength(divisor); | |
var dividendLen = GetLength(dividend); | |
if (divisorLen <= 1) | |
{ | |
ulong rem = 0; | |
var div = divisor[0]; | |
quotient = new uint[dividendLen]; | |
remainder = new uint[1]; | |
for (var i = dividendLen - 1; i >= 0; i--) | |
{ | |
rem *= hiBit; | |
rem += dividend[i]; | |
var q = rem / div; | |
rem -= q * div; | |
quotient[i] = (uint)q; | |
} | |
remainder[0] = (uint)rem; | |
return; | |
} | |
if (dividendLen >= divisorLen) | |
{ | |
var shift = GetNormalizeShift(divisor[divisorLen - 1]); | |
var normDividend = new uint[dividendLen + 1]; | |
var normDivisor = new uint[divisorLen]; | |
Normalize(dividend, dividendLen, normDividend, shift); | |
Normalize(divisor, divisorLen, normDivisor, shift); | |
quotient = new uint[dividendLen - divisorLen + 1]; | |
for (var j = dividendLen - divisorLen; j >= 0; j--) | |
{ | |
var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1]; | |
var qj = dx / normDivisor[divisorLen - 1]; | |
dx -= qj * normDivisor[divisorLen - 1]; | |
do | |
{ | |
if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2]) | |
break; | |
qj -= 1L; | |
dx += normDivisor[divisorLen - 1]; | |
} while (dx < hiBit); | |
ulong di = 0; | |
ulong dj; | |
var index = 0; | |
while (index < divisorLen) | |
{ | |
var dqj = normDivisor[index] * qj; | |
dj = normDividend[index + j] - (uint)dqj - di; | |
normDividend[index + j] = (uint)dj; | |
dqj = dqj >> 32; | |
dj = dj >> 32; | |
di = dqj - dj; | |
index++; | |
} | |
dj = normDividend[j + divisorLen] - di; | |
normDividend[j + divisorLen] = (uint)dj; | |
quotient[j] = (uint)qj; | |
if ((long)dj < 0) | |
{ | |
quotient[j]--; | |
ulong sum = 0; | |
for (index = 0; index < divisorLen; index++) | |
{ | |
sum = normDivisor[index] + normDividend[j + index] + sum; | |
normDividend[j + index] = (uint)sum; | |
sum = sum >> 32; | |
} | |
sum += normDividend[j + divisorLen]; | |
normDividend[j + divisorLen] = (uint)sum; | |
} | |
} | |
remainder = Unnormalize(normDividend, shift); | |
return; | |
} | |
quotient = new uint[1]; | |
remainder = dividend; | |
} | |
private static int GetLength(uint[] uints) | |
{ | |
var index = uints.Length - 1; | |
while (index >= 0 && uints[index] == 0) | |
index--; | |
return index + 1; | |
} | |
private static int GetNormalizeShift(uint ui) | |
{ | |
var shift = 0; | |
if ((ui & 0xffff0000) == 0) | |
{ | |
ui = ui << 16; | |
shift += 16; | |
} | |
if ((ui & 0xff000000) == 0) | |
{ | |
ui = ui << 8; | |
shift += 8; | |
} | |
if ((ui & 0xf0000000) == 0) | |
{ | |
ui = ui << 4; | |
shift += 4; | |
} | |
if ((ui & 0xc0000000) == 0) | |
{ | |
ui = ui << 2; | |
shift += 2; | |
} | |
if ((ui & 0x80000000) == 0) | |
shift++; | |
return shift; | |
} | |
private static uint[] Unnormalize(uint[] normalized, int shift) | |
{ | |
var len = GetLength(normalized); | |
var unnormalized = new uint[len]; | |
if (shift > 0) | |
{ | |
var rshift = 32 - shift; | |
uint r = 0; | |
for (var i = len - 1; i >= 0; i--) | |
{ | |
unnormalized[i] = (normalized[i] >> shift) | r; | |
r = normalized[i] << rshift; | |
} | |
} | |
else | |
{ | |
for (var j = 0; j < len; j++) | |
unnormalized[j] = normalized[j]; | |
} | |
return unnormalized; | |
} | |
private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift) | |
{ | |
int i; | |
uint n = 0; | |
if (shift > 0) | |
{ | |
var rShift = 32 - shift; | |
for (i = 0; i < len; i++) | |
{ | |
normalized[i] = (unormalized[i] << shift) | n; | |
n = unormalized[i] >> rShift; | |
} | |
} | |
else | |
{ | |
i = 0; | |
while (i < len) | |
{ | |
normalized[i] = unormalized[i]; | |
i++; | |
} | |
} | |
while (i < normalized.Length) | |
normalized[i++] = 0; | |
if (n != 0) | |
normalized[len] = n; | |
} | |
public static xIntX Remainder(xIntX dividend, xIntX divisor) | |
{ | |
DivRem(dividend, divisor, out var remainder); | |
return remainder; | |
} | |
public static xIntX Max(xIntX left, xIntX right) | |
{ | |
return left.CompareTo(right) < 0 ? right : left; | |
} | |
public static xIntX Min(xIntX left, xIntX right) | |
{ | |
return left.CompareTo(right) <= 0 ? left : right; | |
} | |
public static xIntX operator %(xIntX dividend, xIntX divisor) | |
{ | |
return Remainder(dividend, divisor); | |
} | |
public static xIntX operator /(xIntX dividend, xIntX divisor) | |
{ | |
return Divide(dividend, divisor); | |
} | |
public ulong[] ToUIn64Array() | |
{ | |
var al = Data.Length >> 1; | |
if (al * 2 != Data.Length) | |
al++; | |
var arr = new ulong[al]; | |
Buffer.BlockCopy(Data, 0, arr, 0, Data.Length << 2); | |
return arr; | |
} | |
public uint[] ToUIn32Array() | |
{ | |
return Data; | |
} | |
public byte[] ToByteArray() | |
{ | |
var ba = new byte[Data.Length * DataSize]; | |
Buffer.BlockCopy(Data, 0, ba, 0, Data.Length * DataSize); | |
return ba; | |
} | |
private void TrimToMsb() | |
{ | |
var dataUsed = Data.Length; | |
while (dataUsed > 1 && Data[dataUsed - 1] == 0) | |
--dataUsed; | |
if (dataUsed != Data.Length) | |
{ | |
var tData = new uint[dataUsed]; | |
for (var i = 0; i < dataUsed; i++) | |
tData[i] = Data[i]; | |
Data = (uint[])tData.Clone(); | |
} | |
} | |
public static xIntX Multiply(xIntX left, xIntX right) | |
{ | |
if (left == 0 || right == 0) | |
return 0; | |
if (left == 1 && right != 1) | |
return right; | |
if (left != 1 && right == 1) | |
return left; | |
if (left == 1 && right == 1) | |
return 1; | |
var xInts = left.Data; | |
var yInts = right.Data; | |
var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1]; | |
for (var i = 0; i < xInts.Length; i++) | |
{ | |
var index = i; | |
ulong remainder = 0; | |
foreach (var yi in yInts) | |
{ | |
remainder = remainder + (ulong)xInts[i] * yi + mulInts[index]; | |
mulInts[index++] = (uint)remainder; | |
remainder = remainder >> 32; | |
} | |
while (remainder != 0) | |
{ | |
remainder += mulInts[index]; | |
mulInts[index++] = (uint)remainder; | |
remainder = remainder >> 32; | |
} | |
} | |
return new xIntX(left.Sign * right.Sign, mulInts, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator *(xIntX left, xIntX right) | |
{ | |
return Multiply(left, right); | |
} | |
public static xIntX operator >> (xIntX value, int shift) | |
{ | |
if (shift == 0) | |
return value; | |
if (shift == int.MinValue) | |
return value << int.MaxValue << 1; | |
if (shift < 0) | |
return value << -shift; | |
var xd = value.Data; | |
var shiftAmount = 32; | |
var invShift = 0; | |
var bufLen = xd.Length; | |
while (bufLen > 1 && xd[bufLen - 1] == 0) | |
bufLen--; | |
for (var count = shift; count > 0; count -= shiftAmount) | |
{ | |
if (count < shiftAmount) | |
{ | |
shiftAmount = count; | |
invShift = 32 - shiftAmount; | |
} | |
ulong carry = 0; | |
for (var i = bufLen - 1; i >= 0; i--) | |
{ | |
var val = (ulong)xd[i] >> shiftAmount; | |
val |= carry; | |
carry = (ulong)xd[i] << invShift; | |
xd[i] = (uint)val; | |
} | |
} | |
return new xIntX(value.Sign, xd, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator <<(xIntX value, int shift) | |
{ | |
if (shift == 0) | |
return value; | |
if (shift == int.MinValue) | |
return value >> int.MaxValue >> 1; | |
if (shift < 0) | |
return value >> -shift; | |
var digitShift = shift / 32; | |
var smallShift = shift - digitShift * 32; | |
var xd = value.Data; | |
var xl = xd.Length; | |
var zd = new uint[xl + digitShift + 1]; | |
if (smallShift == 0) | |
{ | |
for (var index = 0; index < xl; ++index) | |
zd[index + digitShift] = xd[index]; | |
} | |
else | |
{ | |
var carryShift = 32 - smallShift; | |
uint carry = 0; | |
int index; | |
for (index = 0; index < xl; ++index) | |
{ | |
var rot = xd[index]; | |
zd[index + digitShift] = (rot << smallShift) | carry; | |
carry = rot >> carryShift; | |
} | |
zd[index + digitShift] = carry; | |
} | |
return new xIntX(value.Sign, zd, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator |(xIntX left, xIntX right) | |
{ | |
if (left == 0) | |
return right; | |
if (right == 0) | |
return left; | |
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; | |
var lExt = left.Sign < 0 ? uint.MaxValue : 0U; | |
var rExt = right.Sign < 0 ? uint.MaxValue : 0U; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < left.Data.Length ? left.Data[i] : lExt; | |
var yu = i < right.Data.Length ? right.Data[i] : rExt; | |
z[i] = xu | yu; | |
} | |
return new xIntX(left.Sign * right.Sign, z, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator ^(xIntX left, xIntX right) | |
{ | |
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; | |
var lExt = left.Sign < 0 ? uint.MaxValue : 0U; | |
var rExt = right.Sign < 0 ? uint.MaxValue : 0U; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < left.Data.Length ? left.Data[i] : lExt; | |
var yu = i < right.Data.Length ? right.Data[i] : rExt; | |
z[i] = xu ^ yu; | |
} | |
return new xIntX(left.Sign * right.Sign, z, DataBitWidth, _unsigned); | |
} | |
public static xIntX operator &(xIntX left, xIntX right) | |
{ | |
if (left == 0 || right == 0) | |
return 0; | |
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; | |
var lExt = left.Sign < 0 ? uint.MaxValue : 0U; | |
var rExt = right.Sign < 0 ? uint.MaxValue : 0U; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < left.Data.Length ? left.Data[i] : lExt; | |
var yu = i < right.Data.Length ? right.Data[i] : rExt; | |
z[i] = xu & yu; | |
} | |
return new xIntX(left.Sign * right.Sign, z, DataBitWidth, _unsigned); | |
} | |
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 xIntX Pow(xIntX value, xIntX exponent, int bitLength) | |
{ | |
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"); | |
var result = new xIntX("1", bitLength, _unsigned); | |
while (exponent != 0) | |
{ | |
if ((exponent & 1) != 0) | |
result *= value; | |
exponent >>= 1; | |
value *= value; | |
} | |
return result; | |
} | |
/// <summary> | |
/// Works well, not as good as BigInteger | |
/// </summary> | |
public static BigInteger ModPow(BigInteger n, BigInteger e, BigInteger m) | |
{ | |
var n1 = n; | |
var e1 = e; | |
if (e1 == 0) | |
return 1; | |
if (e1 == 1) | |
return n1 % m; | |
if (e1 == 2) | |
return n1 * n1 % m; | |
n1 %= m; | |
BigInteger r = 1; | |
if ((e1 & 1) == 1) | |
r = n1; | |
while (e1 > 1) | |
{ | |
e1 >>= 1; | |
n1 = n1 * n1 % m; | |
if ((e1 & 1) == 1) | |
r = r * n1 % m; | |
} | |
return r; | |
} | |
public static int GetSign(uint[] value) | |
{ | |
var allZero = true; | |
for (var i = 0; i < value.Length; i++) | |
if (value[i] != 0) | |
{ | |
allZero = false; | |
break; | |
} | |
if (allZero) | |
return 0; | |
return (value[value.Length - 1] & HiNeg) == 0 ? 1 : -1; | |
} | |
private static int GetDataUsed(uint[] array) | |
{ | |
var neg = GetSign(array) < 0; | |
var dataUsed = array.Length; | |
if (!neg) | |
{ | |
while (dataUsed > 1 && array[dataUsed - 1] == 0) | |
--dataUsed; | |
if (dataUsed == 0) | |
dataUsed = 1; | |
} | |
return dataUsed; | |
} | |
public int GetDecimalPlaces(xIntX a) | |
{ | |
var dPlaces = 0; | |
if (a.Sign == 0) | |
return 1; | |
if (a.Sign < 0) | |
try | |
{ | |
a = -a; | |
} | |
catch (Exception ex) | |
{ | |
return 0; | |
} | |
var biRadix = new xIntX(10, DataBitWidth, _unsigned); | |
while (a > 0) | |
try | |
{ | |
Divide(a, biRadix, out var remainder, out var quotient); | |
a = quotient; | |
dPlaces++; | |
} | |
catch (Exception ex) | |
{ | |
break; | |
} | |
return dPlaces; | |
} | |
private 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 (xIntX approximateRoot, BigRational realRoot) Sqrt() | |
{ | |
var n = (BigRational)this; | |
var r = n.Sqrt(); | |
return (r.WholePart, r); | |
} | |
public xIntX Pow(int e) | |
{ | |
var ans = this; | |
if (e == 1) | |
return ans; | |
if (e == 0) | |
return 1; | |
for (var i = 1; i != e; i++) | |
ans *= this; | |
return ans; | |
} | |
public static double Log(xIntX value, double baseValue) | |
{ | |
var c = 0.0; | |
var d = 0.5; | |
var dataLength = value.DataUsed; | |
var topBits = 0; | |
var x = value.Data[dataLength - 1]; | |
while (x > 0) | |
{ | |
x >>= 1; | |
topBits++; | |
} | |
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.Data[index] & (int)bit) != 0) | |
c += d; | |
d *= 0.5; | |
} | |
bit = 2147483648U; | |
} | |
return (Math.Log(c) + 0.69314718055994530941723212145818 * bitLength) / Math.Log(baseValue); | |
} | |
public static List<xIntX> GetFactors(xIntX n) | |
{ | |
var Factors = new List<xIntX>(); | |
var s = (xIntX)1 << ((int)Math.Ceiling(Log(n, 2)) >> 1); | |
var a = (xIntX)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 xIntX GreatestCommonDivisor(xIntX a, xIntX b) | |
{ | |
while (b > 0) | |
{ | |
var r = a % b; | |
a = b; | |
b = r; | |
} | |
return a; | |
} | |
public static xIntX LeastCommonMultiple(xIntX a, xIntX b) | |
{ | |
return a * b / a.Gcd(b); | |
} | |
public static double Log10(xIntX value) | |
{ | |
return Log(value, 10.0); | |
} | |
public static double LogN(xIntX value) | |
{ | |
return Log(value, 2.0); | |
} | |
public void ConstructFromArray(byte[] value, int bitLength) | |
{ | |
var minSize = value.Length / DataSize; | |
if (value == null) | |
throw new ArgumentNullException("value"); | |
DataBitWidth = bitLength; | |
DataLength = DataBitWidth >> 5; | |
var byteCount = value.Length; | |
var isNegative = _unsigned == false && byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80; | |
var unalignedBytes = byteCount % DataSize; | |
var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1); | |
Data = new uint[Math.Max(dwordCount, DataLength)]; | |
if (byteCount == 0) | |
return; | |
int curDword, curByte, byteInDword; | |
curByte = 3; | |
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) | |
{ | |
byteInDword = 0; | |
while (byteInDword < DataSize) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= value[curByte]; | |
curByte--; | |
byteInDword++; | |
} | |
curByte += 8; | |
} | |
if (unalignedBytes != 0) | |
{ | |
if (isNegative) | |
Data[dwordCount - 1] = 0xffffffff; | |
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) | |
{ | |
Data[curDword] <<= 8; | |
Data[curDword] |= value[curByte]; | |
} | |
} | |
} | |
private class xIntXConverter : 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 xIntX(0, DataBitWidth, _unsigned); | |
} | |
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); | |
} | |
} | |
} | |
public class xIntXComparer : IComparer<xIntX> | |
{ | |
public int Compare(xIntX left, xIntX right) | |
{ | |
return left.CompareTo(right); | |
} | |
public bool Equals(xIntX left, xIntX right) | |
{ | |
if (left == null || right == null) | |
return false; | |
return left.Equals(right); | |
} | |
public int GetHashCode(xIntX obj) | |
{ | |
return obj.GetHashCode(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment