Int128 Bit Class
Jun-11,2021: Obsolete Use xIntX Instead.
using System; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Text; [Serializable] [StructLayout(LayoutKind.Sequential)] [TypeConverter(typeof(Int128Converter))] [DebuggerDisplay("{DDisplay}")] public struct Int128 : IComparable<Int128>, IComparable, IEquatable<Int128>, IConvertible, IFormattable { public ulong _hi; public ulong _lo; private const ulong HiNeg = 0x8000000000000000; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DDisplay => "0x" + ToString("X1"); public static Int128 Zero; public static Int128 Ten = new Int128(10); public static Int128 One = new Int128(1); public static Int128 MaxValue = GetMaxValue(); public static Int128 MinValue = GetMinValue(); private static Int128 GetMaxValue() { return new Int128(long.MaxValue, ulong.MaxValue); } private static Int128 GetMinValue() { return new Int128(0x8000000000000000, 0); } /// <summary> /// Either base10 or base 16 /// </summary> public Int128(string value) { TryParse(value, out var result); _hi = result._hi; _lo = result._lo; } public Int128(byte value) { _hi = 0; _lo = value; } public Int128(bool value) { _hi = 0; _lo = (ulong) (value ? 1 : 0); } public Int128(char value) { _hi = 0; _lo = value; } public Int128(decimal value) { if (value < 0) { var n = -new Int128(-value); _hi = n._hi; _lo = n._lo; return; } var bits = decimal.GetBits(value); _hi = (uint) bits[2]; _lo = (uint) bits[0] | ((ulong) bits[1] << 32); } public Int128(double value) : this((decimal) value) { } public Int128(float value) : this((decimal) value) { } public Int128(short value) { if (value < 0) { var n = -new Int128(-(value + 1)) - 1; _hi = n._hi; _lo = n._lo; return; } _hi = 0; _lo = (ulong) value; } public Int128(int value) { if (value < 0) { var n = -new Int128(-(value + 1)) - 1; _hi = n._hi; _lo = n._lo; return; } _hi = 0; _lo = (ulong) value; } public Int128(long value) { if (value < 0) { var n = -new Int128(-(value + 1)) - 1; _hi = n._hi; _lo = n._lo; return; } _hi = 0; _lo = (ulong) value; } public Int128(sbyte value) { if (value < 0) { var n = -new Int128(-(value + 1)) - 1; _hi = n._hi; _lo = n._lo; return; } _hi = 0; _lo = (ulong) value; } public Int128(ushort value) { _hi = 0; _lo = value; } public Int128(uint value) { _hi = 0; _lo = value; } public Int128(ulong value) { _hi = 0; _lo = value; } public Int128(Guid value) : this(value.ToByteArray()) { } public Int128(byte[] value) { if (value == null) throw new ArgumentNullException("value"); if (value.Length != 16) throw new ArgumentException(null, "value"); _hi = BitConverter.ToUInt64(value, 8); _lo = BitConverter.ToUInt64(value, 0); } public Int128(ulong hi, ulong lo) { _hi = hi; _lo = lo; } public Int128(int sign, uint[] ints) { if (ints == null) throw new ArgumentNullException("ints"); var lo = new byte[8]; var hi = new byte[8]; if (ints.Length > 0) { Array.Copy(BitConverter.GetBytes(ints[0]), 0, lo, 0, 4); if (ints.Length > 1) { Array.Copy(BitConverter.GetBytes(ints[1]), 0, lo, 4, 4); if (ints.Length > 2) { Array.Copy(BitConverter.GetBytes(ints[2]), 0, hi, 0, 4); if (ints.Length > 3) Array.Copy(BitConverter.GetBytes(ints[3]), 0, hi, 4, 4); } } } _lo = BitConverter.ToUInt64(lo, 0); _hi = BitConverter.ToUInt64(hi, 0); if (sign < 0) _hi |= HiNeg; else _hi &= ~HiNeg; } public int BitWidth { get { Int128 bitWidth = 1; var v = this; while ((v >>= 1) > 0) bitWidth++; if (bitWidth < 8) bitWidth = 8; while (bitWidth % 8 != 0) bitWidth++; return (int) bitWidth; } } public int Sign { get { if (_hi == 0 && _lo == 0) return 0; return (_hi & HiNeg) == 0 ? 1 : -1; } } public override int GetHashCode() { return _hi.GetHashCode() ^ _lo.GetHashCode(); } public override bool Equals(object obj) { return base.Equals(obj); } public bool Equals(Int128 obj) { return _hi == obj._hi && _lo == obj._lo; } 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 min; int.TryParse(format.Substring(1).Trim(), out min); return ToHexString(ch == 'X', min); } if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd') throw new NotSupportedException("Not supported format: " + format); } return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo))); } private string ToHexString(bool caps, int min) { var sb = new StringBuilder(); var x = caps ? "X" : "x"; if (min < 0 || min > 16 || _hi != 0) { sb.Append(min > 16 ? _hi.ToString(x + (min - 16)) : _hi.ToString(x)); sb.Append(_lo.ToString(x + "16")); } else { sb.Append(_lo.ToString(x + min)); } return sb.ToString(); } private string ToString(NumberFormatInfo info) { if (Sign == 0) return "0"; var sb = new StringBuilder(); var current = this; current._hi &= ~HiNeg; Int128 r; while (true) { current = DivRem(current, Ten, out r); if (r._lo > 0 || current.Sign != 0 || sb.Length == 0) sb.Insert(0, (char) ('0' + r._lo)); if (current.Sign == 0) break; } var s = sb.ToString(); if (Sign < 0 && s != "0") return info.NegativeSign + s; return s; } TypeCode IConvertible.GetTypeCode() { return TypeCode.Object; } bool IConvertible.ToBoolean(IFormatProvider provider) { return (bool) this; } byte IConvertible.ToByte(IFormatProvider provider) { return (byte) this; } char IConvertible.ToChar(IFormatProvider provider) { return (char) this; } DateTime IConvertible.ToDateTime(IFormatProvider provider) { throw new InvalidCastException(); } decimal IConvertible.ToDecimal(IFormatProvider provider) { return (decimal) this; } double IConvertible.ToDouble(IFormatProvider provider) { return (double) this; } short IConvertible.ToInt16(IFormatProvider provider) { return (short) this; } int IConvertible.ToInt32(IFormatProvider provider) { return (int) this; } long IConvertible.ToInt64(IFormatProvider provider) { return (int) this; } sbyte IConvertible.ToSByte(IFormatProvider provider) { return (sbyte) this; } float IConvertible.ToSingle(IFormatProvider provider) { return (float) this; } string IConvertible.ToString(IFormatProvider provider) { return ToString(null, provider); } public bool TryConvert(Type conversionType, IFormatProvider provider, out object value) { if (conversionType == typeof(bool)) { value = (bool) this; return true; } if (conversionType == typeof(byte)) { value = (byte) this; return true; } if (conversionType == typeof(char)) { value = (char) this; return true; } if (conversionType == typeof(decimal)) { value = (decimal) this; return true; } if (conversionType == typeof(double)) { value = (double) this; return true; } if (conversionType == typeof(short)) { value = (short) this; return true; } if (conversionType == typeof(int)) { value = (int) this; return true; } if (conversionType == typeof(long)) { value = (long) this; return true; } if (conversionType == typeof(sbyte)) { value = (sbyte) this; return true; } if (conversionType == typeof(float)) { value = (float) this; return true; } if (conversionType == typeof(string)) { value = ToString(null, provider); return true; } if (conversionType == typeof(ushort)) { value = (ushort) this; return true; } if (conversionType == typeof(uint)) { value = (uint) this; return true; } if (conversionType == typeof(ulong)) { value = (ulong) this; return true; } if (conversionType == typeof(byte[])) { value = ToByteArray(); return true; } if (conversionType == typeof(Guid)) { value = new Guid(ToByteArray()); return true; } value = null; return false; } public static Int128 Parse(string value) { return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } public static Int128 Parse(string value, NumberStyles style) { return Parse(value, style, NumberFormatInfo.CurrentInfo); } public static Int128 Parse(string value, IFormatProvider provider) { return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } public static Int128 Parse(string value, NumberStyles style, IFormatProvider provider) { Int128 result; if (!TryParse(value, style, provider, out result)) throw new ArgumentException(null, "value"); return result; } public static bool TryParse(string value, out Int128 result) { return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int128 result) { result = Zero; if (string.IsNullOrEmpty(value)) return false; if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase)) { style |= NumberStyles.AllowHexSpecifier; value = value.Substring(1); } else { if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { style |= NumberStyles.AllowHexSpecifier; value = value.Substring(2); } } if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier) return TryParseHex(value, out result); return TryParseNum(value, out result); } private static bool TryParseHex(string value, out Int128 result) { if (value.Length > 32) throw new OverflowException(); result = Zero; var hi = false; var pos = 0; for (var i = value.Length - 1; i >= 0; i--) { var ch = value[i]; ulong b; if (ch >= '0' && ch <= '9') b = (ulong) (ch - '0'); else if (ch >= 'A' && ch <= 'F') b = (ulong) (ch - 'A' + 10); else if (ch >= 'a' && ch <= 'f') b = (ulong) (ch - 'a' + 10); else return false; if (hi) { result._hi |= b << pos; pos += 4; } else { result._lo |= b << pos; pos += 4; if (pos == 64) { pos = 0; hi = true; } } } return true; } private static bool TryParseNum(string value, out Int128 result) { result = Zero; foreach (var ch in value) { byte b; if (ch >= '0' && ch <= '9') b = (byte) (ch - '0'); else return false; result = Ten * result; result += b; } return true; } public object ToType(Type conversionType, IFormatProvider provider) { object value; if (TryConvert(conversionType, provider, out value)) return value; throw new InvalidCastException(); } ushort IConvertible.ToUInt16(IFormatProvider provider) { if (_hi != 0) throw new OverflowException(); return Convert.ToUInt16(_lo); } uint IConvertible.ToUInt32(IFormatProvider provider) { if (_hi != 0) throw new OverflowException(); return Convert.ToUInt32(_lo); } ulong IConvertible.ToUInt64(IFormatProvider provider) { if (_hi != 0) throw new OverflowException(); return _lo; } int IComparable.CompareTo(object obj) { return Compare(this, obj); } public static int Compare(Int128 left, object right) { if (right is Int128) return Compare(left, (Int128) right); if (right is bool) return Compare(left, new Int128((bool) right)); if (right is byte) return Compare(left, new Int128((byte) right)); if (right is char) return Compare(left, new Int128((char) right)); if (right is decimal) return Compare(left, new Int128((decimal) right)); if (right is double) return Compare(left, new Int128((double) right)); if (right is short) return Compare(left, new Int128((short) right)); if (right is int) return Compare(left, new Int128((int) right)); if (right is long) return Compare(left, new Int128((long) right)); if (right is sbyte) return Compare(left, new Int128((sbyte) right)); if (right is float) return Compare(left, new Int128((float) right)); if (right is ushort) return Compare(left, new Int128((ushort) right)); if (right is uint) return Compare(left, new Int128((uint) right)); if (right is ulong) return Compare(left, new Int128((ulong) right)); var bytes = right as byte[]; if (bytes != null && bytes.Length != 16) return Compare(left, new Int128(bytes)); if (right is Guid) return Compare(left, new Int128((Guid) right)); throw new ArgumentException(); } public byte[] ToByteArray() { var bytes = new byte[16]; Buffer.BlockCopy(BitConverter.GetBytes(_lo), 0, bytes, 0, 8); Buffer.BlockCopy(BitConverter.GetBytes(_hi), 0, bytes, 8, 8); return bytes; } public static int Compare(Int128 left, Int128 right) { if (left.Sign < 0) { if (right.Sign >= 0) return -1; var xhi = left._hi & ~HiNeg; var yhi = right._hi & ~HiNeg; if (xhi != yhi) return -xhi.CompareTo(yhi); return -left._lo.CompareTo(right._lo); } if (right.Sign < 0) return 1; if (left._hi != right._hi) return left._hi.CompareTo(right._hi); return left._lo.CompareTo(right._lo); } public int CompareTo(Int128 value) { return Compare(this, value); } public static implicit operator Int128(bool value) { return new Int128(value); } public static implicit operator Int128(byte value) { return new Int128(value); } public static implicit operator Int128(char value) { return new Int128(value); } public static explicit operator Int128(decimal value) { return new Int128(value); } public static explicit operator Int128(double value) { return new Int128(value); } public static implicit operator Int128(short value) { return new Int128(value); } public static implicit operator Int128(int value) { return new Int128(value); } public static implicit operator Int128(long value) { return new Int128(value); } public static implicit operator Int128(sbyte value) { return new Int128(value); } public static explicit operator Int128(float value) { return new Int128(value); } public static implicit operator Int128(ushort value) { return new Int128(value); } public static implicit operator Int128(uint value) { return new Int128(value); } public static implicit operator Int128(ulong value) { return new Int128(value); } public static explicit operator bool(Int128 value) { return value.Sign != 0; } public static explicit operator byte(Int128 value) { if (value.Sign == 0) return 0; if (value.Sign < 0 || value._lo > 0xFF) throw new OverflowException(); return (byte) value._lo; } public static explicit operator char(Int128 value) { if (value.Sign == 0) return (char) 0; if (value.Sign < 0 || value._lo > 0xFFFF) throw new OverflowException(); return (char) (ushort) value._lo; } public static explicit operator decimal(Int128 value) { if (value.Sign == 0) return 0; return new decimal((int) (value._lo & 0xFFFFFFFF), (int) (value._lo >> 32), (int) (value._hi & 0xFFFFFFFF), value.Sign < 0, 0); } public static explicit operator double(Int128 value) { if (value.Sign == 0) return 0; double d; var nfi = CultureInfo.InvariantCulture.NumberFormat; if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out d)) throw new OverflowException(); return d; } public static explicit operator float(Int128 value) { if (value.Sign == 0) return 0; float f; var nfi = CultureInfo.InvariantCulture.NumberFormat; if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out f)) throw new OverflowException(); return f; } public static explicit operator short(Int128 value) { if (value.Sign == 0) return 0; if (value._lo > 0x8000) throw new OverflowException(); if (value._lo == 0x8000 && value.Sign > 0) throw new OverflowException(); return (short) ((int) value._lo * value.Sign); } public static explicit operator int(Int128 value) { if (value.Sign == 0) return 0; if (value._lo > 0x80000000) throw new OverflowException(); if (value._lo == 0x80000000 && value.Sign > 0) throw new OverflowException(); return (int) value._lo * value.Sign; } public static explicit operator long(Int128 value) { if (value.Sign == 0) return 0; if (value._lo > long.MaxValue) throw new OverflowException(); return (long) value._lo * value.Sign; } public static explicit operator uint(Int128 value) { if (value.Sign == 0) return 0; if (value.Sign < 0 || value._lo > uint.MaxValue) throw new OverflowException(); return (uint) value._lo; } public static explicit operator ushort(Int128 value) { if (value.Sign == 0) return 0; if (value.Sign < 0 || value._lo > ushort.MaxValue) throw new OverflowException(); return (ushort) value._lo; } public static explicit operator ulong(Int128 value) { if (value.Sign < 0 || value._hi != 0) throw new OverflowException(); return value._lo; } public static bool operator >(Int128 left, Int128 right) { return Compare(left, right) > 0; } public static bool operator <(Int128 left, Int128 right) { return Compare(left, right) < 0; } public static bool operator >=(Int128 left, Int128 right) { return Compare(left, right) >= 0; } public static bool operator <=(Int128 left, Int128 right) { return Compare(left, right) <= 0; } public static bool operator !=(Int128 left, Int128 right) { return Compare(left, right) != 0; } public static bool operator ==(Int128 left, Int128 right) { return Compare(left, right) == 0; } public static Int128 operator +(Int128 value) { return value; } public static Int128 operator -(Int128 value) { return Negate(value); } public static Int128 operator ~(Int128 value) { return -(value + One); } public static Int128 operator ++(Int128 value) { return value + 1; } public static Int128 operator --(Int128 value) { return value - 1; } public static Int128 Negate(Int128 value) { return new Int128(~value._hi, ~value._lo) + 1; } public Int128 ToAbs() { return Abs(this); } public static Int128 Abs(Int128 value) { if (value.Sign < 0) return -value; return value; } public static Int128 operator +(Int128 left, Int128 right) { var add = left; add._hi += right._hi; add._lo += right._lo; if (add._lo < left._lo) add._hi++; return add; } public static Int128 operator -(Int128 left, Int128 right) { return left + -right; } public static Int128 Add(Int128 left, Int128 right) { return left + right; } public static Int128 Subtract(Int128 left, Int128 right) { return left - right; } public static Int128 Divide(Int128 dividend, Int128 divisor) { Int128 integer; return DivRem(dividend, divisor, out integer); } public static Int128 DivRem(Int128 dividend, Int128 divisor, out Int128 remainder) { if (divisor == 0) throw new DivideByZeroException(); uint[] quotient; uint[] rem; DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out quotient, out rem); remainder = new Int128(1, rem); return new Int128(dividend.Sign * divisor.Sign, quotient); } private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder) { const ulong hiBit = 0x100000000; var divisorLen = GetLength(divisor); var dividendLen = GetLength(dividend); if (divisorLen <= 1) { ulong rem = 0; var div = divisor[0]; quotient = new uint[dividendLen]; remainder = new uint[1]; for (var i = dividendLen - 1; i >= 0; i--) { rem *= hiBit; rem += dividend[i]; var q = rem / div; rem -= q * div; quotient[i] = (uint) q; } remainder[0] = (uint) rem; return; } if (dividendLen >= divisorLen) { var shift = GetNormalizeShift(divisor[divisorLen - 1]); var normDividend = new uint[dividendLen + 1]; var normDivisor = new uint[divisorLen]; Normalize(dividend, dividendLen, normDividend, shift); Normalize(divisor, divisorLen, normDivisor, shift); quotient = new uint[dividendLen - divisorLen + 1]; for (var j = dividendLen - divisorLen; j >= 0; j--) { var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1]; var qj = dx / normDivisor[divisorLen - 1]; dx -= qj * normDivisor[divisorLen - 1]; do { if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2]) break; qj -= 1L; dx += normDivisor[divisorLen - 1]; } while (dx < hiBit); long di = 0; long dj; var index = 0; while (index < divisorLen) { var dqj = normDivisor[index] * qj; dj = normDividend[index + j] - (uint) dqj - di; normDividend[index + j] = (uint) dj; dqj = dqj >> 32; dj = dj >> 32; di = (long) dqj - dj; index++; } dj = normDividend[j + divisorLen] - di; normDividend[j + divisorLen] = (uint) dj; quotient[j] = (uint) qj; if (dj < 0) { quotient[j]--; ulong sum = 0; for (index = 0; index < divisorLen; index++) { sum = normDivisor[index] + normDividend[j + index] + sum; normDividend[j + index] = (uint) sum; sum = sum >> 32; } sum += normDividend[j + divisorLen]; normDividend[j + divisorLen] = (uint) sum; } } remainder = Unnormalize(normDividend, shift); return; } quotient = new uint[0]; remainder = dividend; } private static int GetLength(uint[] uints) { var index = uints.Length - 1; while (index >= 0 && uints[index] == 0) index--; return index + 1; } private static int GetNormalizeShift(uint ui) { var shift = 0; if ((ui & 0xffff0000) == 0) { ui = ui << 16; shift += 16; } if ((ui & 0xff000000) == 0) { ui = ui << 8; shift += 8; } if ((ui & 0xf0000000) == 0) { ui = ui << 4; shift += 4; } if ((ui & 0xc0000000) == 0) { ui = ui << 2; shift += 2; } if ((ui & 0x80000000) == 0) shift++; return shift; } private static uint[] Unnormalize(uint[] normalized, int shift) { var len = GetLength(normalized); var unormalized = new uint[len]; if (shift > 0) { var rshift = 32 - shift; uint r = 0; for (var i = len - 1; i >= 0; i--) { unormalized[i] = (normalized[i] >> shift) | r; r = normalized[i] << rshift; } } else { for (var j = 0; j < len; j++) unormalized[j] = normalized[j]; } return unormalized; } 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 Int128 Remainder(Int128 dividend, Int128 divisor) { Int128 remainder; DivRem(dividend, divisor, out remainder); return remainder; } public static Int128 operator %(Int128 dividend, Int128 divisor) { return Remainder(dividend, divisor); } public static Int128 operator /(Int128 dividend, Int128 divisor) { return Divide(dividend, divisor); } public ulong[] ToUIn64Array() { return new[] {_hi, _lo}; } public uint[] ToUIn32Array() { var ints = new uint[4]; var lob = BitConverter.GetBytes(_lo); var hib = BitConverter.GetBytes(_hi); Buffer.BlockCopy(lob, 0, ints, 0, 4); Buffer.BlockCopy(lob, 4, ints, 4, 4); Buffer.BlockCopy(hib, 0, ints, 8, 4); Buffer.BlockCopy(hib, 4, ints, 12, 4); return ints; } public static Int128 Multiply(Int128 left, Int128 right) { var xInts = left.ToUIn32Array(); var yInts = right.ToUIn32Array(); var mulInts = new uint[8]; 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 Int128(left.Sign * right.Sign, mulInts); } public static Int128 operator *(Int128 left, Int128 right) { return Multiply(left, right); } public static Int128 operator >>(Int128 value, int shift) { if (shift == 0) return value; if (shift < 0) return value << -shift; shift = shift % 128; var shifted = new Int128(); if (shift > 63) { shifted._lo = value._hi >> (shift - 64); shifted._hi = 0; } else { shifted._hi = value._hi >> shift; shifted._lo = (value._hi << (64 - shift)) | (value._lo >> shift); } return shifted; } public static Int128 operator <<(Int128 value, int shift) { if (shift == 0) return value; if (shift < 0) return value >> -shift; shift = shift % 128; var shifted = new Int128(); if (shift > 63) { shifted._hi = value._lo << (shift - 64); shifted._lo = 0; } else { var ul = value._lo >> (64 - shift); shifted._hi = ul | (value._hi << shift); shifted._lo = value._lo << shift; } return shifted; } public static Int128 operator |(Int128 left, Int128 right) { if (left == 0) return right; if (right == 0) return left; var x = left.ToUIn32Array(); var y = right.ToUIn32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left.Sign < 0 ? uint.MaxValue : 0; var yExtend = right.Sign < 0 ? uint.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu | yu; } return new Int128(left.Sign * right.Sign, z); } public static Int128 operator ^(Int128 left, Int128 right) { var x = left.ToUIn32Array(); var y = right.ToUIn32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left.Sign < 0 ? uint.MaxValue : 0; var yExtend = right.Sign < 0 ? uint.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu ^ yu; } return new Int128(left.Sign * right.Sign, z); } public static Int128 operator &(Int128 left, Int128 right) { if (left == 0 || right == 0) return Zero; var x = left.ToUIn32Array(); var y = right.ToUIn32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left.Sign < 0 ? uint.MaxValue : 0; var yExtend = right.Sign < 0 ? uint.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu & yu; } return new Int128(left.Sign * right.Sign, z); } public class Int128Converter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) return true; return base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value != null) { Int128 i; if (TryParse($"{value}", out i)) return i; } return new Int128(); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) return true; return base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) return $"{value}"; return base.ConvertTo(context, culture, value, destinationType); } } }