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