using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Numerics; namespace Dirichlet.Numerics { public struct Int128 : IFormattable, IComparable, IComparable, IEquatable { private UInt128 v; private static readonly Int128 minValue = (Int128)((UInt128)1 << 127); private static readonly Int128 maxValue = (Int128)(((UInt128)1 << 127) - 1); private static readonly Int128 zero = (Int128)0; private static readonly Int128 one = (Int128)1; private static readonly Int128 minusOne = (Int128)(-1); public static Int128 MinValue { get { return minValue; } } public static Int128 MaxValue { get { return maxValue; } } public static Int128 Zero { get { return zero; } } public static Int128 One { get { return one; } } public static Int128 MinusOne { get { return minusOne; } } public static Int128 Parse(string value) { Int128 c; if (!TryParse(value, out c)) throw new FormatException(); return c; } 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 format, out Int128 result) { BigInteger a; if (!BigInteger.TryParse(value, style, format, out a)) { result = Int128.Zero; return false; } UInt128.Create(out result.v, a); return true; } public Int128(long value) { UInt128.Create(out v, value); } public Int128(ulong value) { UInt128.Create(out v, value); } public Int128(double value) { UInt128.Create(out v, value); } public Int128(decimal value) { UInt128.Create(out v, value); } public Int128(BigInteger value) { UInt128.Create(out v, value); } public ulong S0 { get { return v.S0; } } public ulong S1 { get { return v.S1; } } public bool IsZero { get { return v.IsZero; } } public bool IsOne { get { return v.IsOne; } } public bool IsPowerOfTwo { get { return v.IsPowerOfTwo; } } public bool IsEven { get { return v.IsEven; } } public bool IsNegative { get { return v.S1 > long.MaxValue; } } public int Sign { get { return IsNegative ? -1 : v.Sign; } } public override string ToString() { return ((BigInteger)this).ToString(); } public string ToString(string format) { return ((BigInteger)this).ToString(format); } public string ToString(IFormatProvider provider) { return ToString(null, provider); } public string ToString(string format, IFormatProvider provider) { return ((BigInteger)this).ToString(format, provider); } public static explicit operator Int128(double a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(sbyte a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(byte a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(short a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(ushort a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(int a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(uint a) { Int128 c; UInt128.Create(out c.v, (ulong)a); return c; } public static implicit operator Int128(long a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static implicit operator Int128(ulong a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static explicit operator Int128(decimal a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static explicit operator Int128(UInt128 a) { Int128 c; c.v = a; return c; } public static explicit operator UInt128(Int128 a) { return a.v; } public static explicit operator Int128(BigInteger a) { Int128 c; UInt128.Create(out c.v, a); return c; } public static explicit operator sbyte(Int128 a) { return (sbyte)a.v.S0; } public static explicit operator byte(Int128 a) { return (byte)a.v.S0; } public static explicit operator short(Int128 a) { return (short)a.v.S0; } public static explicit operator ushort(Int128 a) { return (ushort)a.v.S0; } public static explicit operator int(Int128 a) { return (int)a.v.S0; } public static explicit operator uint(Int128 a) { return (uint)a.v.S0; } public static explicit operator long(Int128 a) { return (long)a.v.S0; } public static explicit operator ulong(Int128 a) { return a.v.S0; } public static explicit operator decimal(Int128 a) { if (a.IsNegative) { UInt128 c; UInt128.Negate(out c, ref a.v); return -(decimal)c; } return (decimal)a.v; } public static implicit operator BigInteger(Int128 a) { if (a.IsNegative) { UInt128 c; UInt128.Negate(out c, ref a.v); return -(BigInteger)c; } return (BigInteger)a.v; } public static explicit operator float(Int128 a) { if (a.IsNegative) { UInt128 c; UInt128.Negate(out c, ref a.v); return -UInt128.ConvertToFloat(ref c); } return UInt128.ConvertToFloat(ref a.v); } public static explicit operator double(Int128 a) { if (a.IsNegative) { UInt128 c; UInt128.Negate(out c, ref a.v); return -UInt128.ConvertToDouble(ref c); } return UInt128.ConvertToDouble(ref a.v); } public static Int128 operator <<(Int128 a, int b) { Int128 c; UInt128.LeftShift(out c.v, ref a.v, b); return c; } public static Int128 operator >>(Int128 a, int b) { Int128 c; UInt128.ArithmeticRightShift(out c.v, ref a.v, b); return c; } public static Int128 operator &(Int128 a, Int128 b) { Int128 c; UInt128.And(out c.v, ref a.v, ref b.v); return c; } public static int operator &(Int128 a, int b) { return (int)(a.v & (uint)b); } public static int operator &(int a, Int128 b) { return (int)(b.v & (uint)a); } public static long operator &(Int128 a, long b) { return (long)(a.v & (ulong)b); } public static long operator &(long a, Int128 b) { return (long)(b.v & (ulong)a); } public static Int128 operator |(Int128 a, Int128 b) { Int128 c; UInt128.Or(out c.v, ref a.v, ref b.v); return c; } public static Int128 operator ^(Int128 a, Int128 b) { Int128 c; UInt128.ExclusiveOr(out c.v, ref a.v, ref b.v); return c; } public static Int128 operator ~(Int128 a) { Int128 c; UInt128.Not(out c.v, ref a.v); return c; } public static Int128 operator +(Int128 a, long b) { Int128 c; if (b < 0) UInt128.Subtract(out c.v, ref a.v, (ulong)(-b)); else UInt128.Add(out c.v, ref a.v, (ulong)b); return c; } public static Int128 operator +(long a, Int128 b) { Int128 c; if (a < 0) UInt128.Subtract(out c.v, ref b.v, (ulong)(-a)); else UInt128.Add(out c.v, ref b.v, (ulong)a); return c; } public static Int128 operator +(Int128 a, Int128 b) { Int128 c; UInt128.Add(out c.v, ref a.v, ref b.v); return c; } public static Int128 operator ++(Int128 a) { Int128 c; UInt128.Add(out c.v, ref a.v, 1); return c; } public static Int128 operator -(Int128 a, long b) { Int128 c; if (b < 0) UInt128.Add(out c.v, ref a.v, (ulong)(-b)); else UInt128.Subtract(out c.v, ref a.v, (ulong)b); return c; } public static Int128 operator -(Int128 a, Int128 b) { Int128 c; UInt128.Subtract(out c.v, ref a.v, ref b.v); return c; } public static Int128 operator +(Int128 a) { return a; } public static Int128 operator -(Int128 a) { Int128 c; UInt128.Negate(out c.v, ref a.v); return c; } public static Int128 operator --(Int128 a) { Int128 c; UInt128.Subtract(out c.v, ref a.v, 1); return c; } public static Int128 operator *(Int128 a, int b) { Int128 c; Multiply(out c, ref a, b); return c; } public static Int128 operator *(int a, Int128 b) { Int128 c; Multiply(out c, ref b, a); return c; } public static Int128 operator *(Int128 a, uint b) { Int128 c; Multiply(out c, ref a, b); return c; } public static Int128 operator *(uint a, Int128 b) { Int128 c; Multiply(out c, ref b, a); return c; } public static Int128 operator *(Int128 a, long b) { Int128 c; Multiply(out c, ref a, b); return c; } public static Int128 operator *(long a, Int128 b) { Int128 c; Multiply(out c, ref b, a); return c; } public static Int128 operator *(Int128 a, ulong b) { Int128 c; Multiply(out c, ref a, b); return c; } public static Int128 operator *(ulong a, Int128 b) { Int128 c; Multiply(out c, ref b, a); return c; } public static Int128 operator *(Int128 a, Int128 b) { Int128 c; Multiply(out c, ref a, ref b); return c; } public static Int128 operator /(Int128 a, int b) { Int128 c; Divide(out c, ref a, b); return c; } public static Int128 operator /(Int128 a, uint b) { Int128 c; Divide(out c, ref a, b); return c; } public static Int128 operator /(Int128 a, long b) { Int128 c; Divide(out c, ref a, b); return c; } public static Int128 operator /(Int128 a, ulong b) { Int128 c; Divide(out c, ref a, b); return c; } public static Int128 operator /(Int128 a, Int128 b) { Int128 c; Divide(out c, ref a, ref b); return c; } public static int operator %(Int128 a, int b) { return Remainder(ref a, b); } public static int operator %(Int128 a, uint b) { return Remainder(ref a, b); } public static long operator %(Int128 a, long b) { return Remainder(ref a, b); } public static long operator %(Int128 a, ulong b) { return Remainder(ref a, b); } public static Int128 operator %(Int128 a, Int128 b) { Int128 c; Remainder(out c, ref a, ref b); return c; } public static bool operator <(Int128 a, UInt128 b) { return a.CompareTo(b) < 0; } public static bool operator <(UInt128 a, Int128 b) { return b.CompareTo(a) > 0; } public static bool operator <(Int128 a, Int128 b) { return LessThan(ref a.v, ref b.v); } public static bool operator <(Int128 a, int b) { return LessThan(ref a.v, b); } public static bool operator <(int a, Int128 b) { return LessThan(a, ref b.v); } public static bool operator <(Int128 a, uint b) { return LessThan(ref a.v, b); } public static bool operator <(uint a, Int128 b) { return LessThan(a, ref b.v); } public static bool operator <(Int128 a, long b) { return LessThan(ref a.v, b); } public static bool operator <(long a, Int128 b) { return LessThan(a, ref b.v); } public static bool operator <(Int128 a, ulong b) { return LessThan(ref a.v, b); } public static bool operator <(ulong a, Int128 b) { return LessThan(a, ref b.v); } public static bool operator <=(Int128 a, UInt128 b) { return a.CompareTo(b) <= 0; } public static bool operator <=(UInt128 a, Int128 b) { return b.CompareTo(a) >= 0; } public static bool operator <=(Int128 a, Int128 b) { return !LessThan(ref b.v, ref a.v); } public static bool operator <=(Int128 a, int b) { return !LessThan(b, ref a.v); } public static bool operator <=(int a, Int128 b) { return !LessThan(ref b.v, a); } public static bool operator <=(Int128 a, uint b) { return !LessThan(b, ref a.v); } public static bool operator <=(uint a, Int128 b) { return !LessThan(ref b.v, a); } public static bool operator <=(Int128 a, long b) { return !LessThan(b, ref a.v); } public static bool operator <=(long a, Int128 b) { return !LessThan(ref b.v, a); } public static bool operator <=(Int128 a, ulong b) { return !LessThan(b, ref a.v); } public static bool operator <=(ulong a, Int128 b) { return !LessThan(ref b.v, a); } public static bool operator >(Int128 a, UInt128 b) { return a.CompareTo(b) > 0; } public static bool operator >(UInt128 a, Int128 b) { return b.CompareTo(a) < 0; } public static bool operator >(Int128 a, Int128 b) { return LessThan(ref b.v, ref a.v); } public static bool operator >(Int128 a, int b) { return LessThan(b, ref a.v); } public static bool operator >(int a, Int128 b) { return LessThan(ref b.v, a); } public static bool operator >(Int128 a, uint b) { return LessThan(b, ref a.v); } public static bool operator >(uint a, Int128 b) { return LessThan(ref b.v, a); } public static bool operator >(Int128 a, long b) { return LessThan(b, ref a.v); } public static bool operator >(long a, Int128 b) { return LessThan(ref b.v, a); } public static bool operator >(Int128 a, ulong b) { return LessThan(b, ref a.v); } public static bool operator >(ulong a, Int128 b) { return LessThan(ref b.v, a); } public static bool operator >=(Int128 a, UInt128 b) { return a.CompareTo(b) >= 0; } public static bool operator >=(UInt128 a, Int128 b) { return b.CompareTo(a) <= 0; } public static bool operator >=(Int128 a, Int128 b) { return !LessThan(ref a.v, ref b.v); } public static bool operator >=(Int128 a, int b) { return !LessThan(ref a.v, b); } public static bool operator >=(int a, Int128 b) { return !LessThan(a, ref b.v); } public static bool operator >=(Int128 a, uint b) { return !LessThan(ref a.v, b); } public static bool operator >=(uint a, Int128 b) { return !LessThan(a, ref b.v); } public static bool operator >=(Int128 a, long b) { return !LessThan(ref a.v, b); } public static bool operator >=(long a, Int128 b) { return !LessThan(a, ref b.v); } public static bool operator >=(Int128 a, ulong b) { return !LessThan(ref a.v, b); } public static bool operator >=(ulong a, Int128 b) { return !LessThan(a, ref b.v); } public static bool operator ==(UInt128 a, Int128 b) { return b.Equals(a); } public static bool operator ==(Int128 a, UInt128 b) { return a.Equals(b); } public static bool operator ==(Int128 a, Int128 b) { return a.v.Equals(b.v); } public static bool operator ==(Int128 a, int b) { return a.Equals(b); } public static bool operator ==(int a, Int128 b) { return b.Equals(a); } public static bool operator ==(Int128 a, uint b) { return a.Equals(b); } public static bool operator ==(uint a, Int128 b) { return b.Equals(a); } public static bool operator ==(Int128 a, long b) { return a.Equals(b); } public static bool operator ==(long a, Int128 b) { return b.Equals(a); } public static bool operator ==(Int128 a, ulong b) { return a.Equals(b); } public static bool operator ==(ulong a, Int128 b) { return b.Equals(a); } public static bool operator !=(UInt128 a, Int128 b) { return !b.Equals(a); } public static bool operator !=(Int128 a, UInt128 b) { return !a.Equals(b); } public static bool operator !=(Int128 a, Int128 b) { return !a.v.Equals(b.v); } public static bool operator !=(Int128 a, int b) { return !a.Equals(b); } public static bool operator !=(int a, Int128 b) { return !b.Equals(a); } public static bool operator !=(Int128 a, uint b) { return !a.Equals(b); } public static bool operator !=(uint a, Int128 b) { return !b.Equals(a); } public static bool operator !=(Int128 a, long b) { return !a.Equals(b); } public static bool operator !=(long a, Int128 b) { return !b.Equals(a); } public static bool operator !=(Int128 a, ulong b) { return !a.Equals(b); } public static bool operator !=(ulong a, Int128 b) { return !b.Equals(a); } public int CompareTo(UInt128 other) { if (IsNegative) return -1; return v.CompareTo(other); } public int CompareTo(Int128 other) { return SignedCompare(ref v, other.S0, other.S1); } public int CompareTo(int other) { return SignedCompare(ref v, (ulong)other, (ulong)(other >> 31)); } public int CompareTo(uint other) { return SignedCompare(ref v, (ulong)other, 0); } public int CompareTo(long other) { return SignedCompare(ref v, (ulong)other, (ulong)(other >> 63)); } public int CompareTo(ulong other) { return SignedCompare(ref v, other, 0); } public int CompareTo(object obj) { if (obj == null) return 1; if (!(obj is Int128)) throw new ArgumentException(); return CompareTo((Int128)obj); } private static bool LessThan(ref UInt128 a, ref UInt128 b) { var as1 = (long)a.S1; var bs1 = (long)b.S1; if (as1 != bs1) return as1 < bs1; return a.S0 < b.S0; } private static bool LessThan(ref UInt128 a, long b) { var as1 = (long)a.S1; var bs1 = b >> 63; if (as1 != bs1) return as1 < bs1; return a.S0 < (ulong)b; } private static bool LessThan(long a, ref UInt128 b) { var as1 = a >> 63; var bs1 = (long)b.S1; if (as1 != bs1) return as1 < bs1; return (ulong)a < b.S0; } private static bool LessThan(ref UInt128 a, ulong b) { var as1 = (long)a.S1; if (as1 != 0) return as1 < 0; return a.S0 < b; } private static bool LessThan(ulong a, ref UInt128 b) { var bs1 = (long)b.S1; if (0 != bs1) return 0 < bs1; return a < b.S0; } private static int SignedCompare(ref UInt128 a, ulong bs0, ulong bs1) { var as1 = a.S1; if (as1 != bs1) return ((long)as1).CompareTo((long)bs1); return a.S0.CompareTo(bs0); } public bool Equals(UInt128 other) { return !IsNegative && v.Equals(other); } public bool Equals(Int128 other) { return v.Equals(other.v); } public bool Equals(int other) { if (other < 0) return v.S1 == ulong.MaxValue && v.S0 == (uint)other; return v.S1 == 0 && v.S0 == (uint)other; } public bool Equals(uint other) { return v.S1 == 0 && v.S0 == other; } public bool Equals(long other) { if (other < 0) return v.S1 == ulong.MaxValue && v.S0 == (ulong)other; return v.S1 == 0 && v.S0 == (ulong)other; } public bool Equals(ulong other) { return v.S1 == 0 && v.S0 == other; } public override bool Equals(object obj) { if (!(obj is Int128)) return false; return Equals((Int128)obj); } public override int GetHashCode() { return v.GetHashCode(); } public static void Multiply(out Int128 c, ref Int128 a, int b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) UInt128.Multiply(out c.v, ref aneg, (uint)(-b)); else { UInt128.Multiply(out c.v, ref aneg, (uint)b); UInt128.Negate(ref c.v); } } else { if (b < 0) { UInt128.Multiply(out c.v, ref a.v, (uint)(-b)); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, (uint)b); } Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b); } public static void Multiply(out Int128 c, ref Int128 a, uint b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Multiply(out c.v, ref aneg, b); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, b); Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b); } public static void Multiply(out Int128 c, ref Int128 a, long b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) UInt128.Multiply(out c.v, ref aneg, (ulong)(-b)); else { UInt128.Multiply(out c.v, ref aneg, (ulong)b); UInt128.Negate(ref c.v); } } else { if (b < 0) { UInt128.Multiply(out c.v, ref a.v, (ulong)(-b)); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, (ulong)b); } Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b); } public static void Multiply(out Int128 c, ref Int128 a, ulong b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Multiply(out c.v, ref aneg, b); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, b); Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b); } public static void Multiply(out Int128 c, ref Int128 a, ref Int128 b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Multiply(out c.v, ref aneg, ref bneg); } else { UInt128.Multiply(out c.v, ref aneg, ref b.v); UInt128.Negate(ref c.v); } } else { if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Multiply(out c.v, ref a.v, ref bneg); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, ref b.v); } Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b); } public static void Divide(out Int128 c, ref Int128 a, int b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) UInt128.Multiply(out c.v, ref aneg, (uint)(-b)); else { UInt128.Multiply(out c.v, ref aneg, (uint)b); UInt128.Negate(ref c.v); } } else { if (b < 0) { UInt128.Multiply(out c.v, ref a.v, (uint)(-b)); UInt128.Negate(ref c.v); } else UInt128.Multiply(out c.v, ref a.v, (uint)b); } Debug.Assert((BigInteger)c == (BigInteger)a / (BigInteger)b); } public static void Divide(out Int128 c, ref Int128 a, uint b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Divide(out c.v, ref aneg, b); UInt128.Negate(ref c.v); } else UInt128.Divide(out c.v, ref a.v, b); Debug.Assert((BigInteger)c == (BigInteger)a / (BigInteger)b); } public static void Divide(out Int128 c, ref Int128 a, long b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) UInt128.Divide(out c.v, ref aneg, (ulong)(-b)); else { UInt128.Divide(out c.v, ref aneg, (ulong)b); UInt128.Negate(ref c.v); } } else { if (b < 0) { UInt128.Divide(out c.v, ref a.v, (ulong)(-b)); UInt128.Negate(ref c.v); } else UInt128.Divide(out c.v, ref a.v, (ulong)b); } Debug.Assert((BigInteger)c == (BigInteger)a / (BigInteger)b); } public static void Divide(out Int128 c, ref Int128 a, ulong b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Divide(out c.v, ref aneg, b); UInt128.Negate(ref c.v); } else UInt128.Divide(out c.v, ref a.v, b); Debug.Assert((BigInteger)c == (BigInteger)a / (BigInteger)b); } public static void Divide(out Int128 c, ref Int128 a, ref Int128 b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Divide(out c.v, ref aneg, ref bneg); } else { UInt128.Divide(out c.v, ref aneg, ref b.v); UInt128.Negate(ref c.v); } } else { if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Divide(out c.v, ref a.v, ref bneg); UInt128.Negate(ref c.v); } else UInt128.Divide(out c.v, ref a.v, ref b.v); } Debug.Assert((BigInteger)c == (BigInteger)a / (BigInteger)b); } public static int Remainder(ref Int128 a, int b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) return (int)UInt128.Remainder(ref aneg, (uint)(-b)); else return -(int)UInt128.Remainder(ref aneg, (uint)b); } else { if (b < 0) return -(int)UInt128.Remainder(ref a.v, (uint)(-b)); else return (int)UInt128.Remainder(ref a.v, (uint)b); } } public static int Remainder(ref Int128 a, uint b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); return -(int)UInt128.Remainder(ref aneg, b); } else return (int)UInt128.Remainder(ref a.v, b); } public static long Remainder(ref Int128 a, long b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b < 0) return (long)UInt128.Remainder(ref aneg, (ulong)(-b)); else return -(long)UInt128.Remainder(ref aneg, (ulong)b); } else { if (b < 0) return -(long)UInt128.Remainder(ref a.v, (ulong)(-b)); else return (long)UInt128.Remainder(ref a.v, (ulong)b); } } public static long Remainder(ref Int128 a, ulong b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); return -(long)UInt128.Remainder(ref aneg, b); } else return (long)UInt128.Remainder(ref a.v, b); } public static void Remainder(out Int128 c, ref Int128 a, ref Int128 b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Remainder(out c.v, ref aneg, ref bneg); } else { UInt128.Remainder(out c.v, ref aneg, ref b.v); UInt128.Negate(ref c.v); } } else { if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.Remainder(out c.v, ref a.v, ref bneg); UInt128.Negate(ref c.v); } else UInt128.Remainder(out c.v, ref a.v, ref b.v); } Debug.Assert((BigInteger)c == (BigInteger)a % (BigInteger)b); } public static Int128 Abs(Int128 a) { if (!a.IsNegative) return a; Int128 c; UInt128.Negate(out c.v, ref a.v); return c; } public static Int128 Square(long a) { if (a < 0) a = -a; Int128 c; UInt128.Square(out c.v, (ulong)a); return c; } public static Int128 Square(Int128 a) { Int128 c; if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Square(out c.v, ref aneg); } else UInt128.Square(out c.v, ref a.v); return c; } public static Int128 Cube(long a) { Int128 c; if (a < 0) { UInt128.Cube(out c.v, (ulong)(-a)); UInt128.Negate(ref c.v); } else UInt128.Cube(out c.v, (ulong)a); return c; } public static Int128 Cube(Int128 a) { Int128 c; if (a < 0) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); UInt128.Cube(out c.v, ref aneg); UInt128.Negate(ref c.v); } else UInt128.Cube(out c.v, ref a.v); return c; } public static void Add(ref Int128 a, long b) { if (b < 0) UInt128.Subtract(ref a.v, (ulong)(-b)); else UInt128.Add(ref a.v, (ulong)b); } public static void Add(ref Int128 a, ref Int128 b) { UInt128.Add(ref a.v, ref b.v); } public static void Subtract(ref Int128 a, long b) { if (b < 0) UInt128.Add(ref a.v, (ulong)(-b)); else UInt128.Subtract(ref a.v, (ulong)b); } public static void Subtract(ref Int128 a, ref Int128 b) { UInt128.Subtract(ref a.v, ref b.v); } public static void Add(ref Int128 a, Int128 b) { UInt128.Add(ref a.v, ref b.v); } public static void Subtract(ref Int128 a, Int128 b) { UInt128.Subtract(ref a.v, ref b.v); } public static void AddProduct(ref Int128 a, ref UInt128 b, int c) { UInt128 product; if (c < 0) { UInt128.Multiply(out product, ref b, (uint)(-c)); UInt128.Subtract(ref a.v, ref product); } else { UInt128.Multiply(out product, ref b, (uint)c); UInt128.Add(ref a.v, ref product); } } public static void AddProduct(ref Int128 a, ref UInt128 b, long c) { UInt128 product; if (c < 0) { UInt128.Multiply(out product, ref b, (ulong)(-c)); UInt128.Subtract(ref a.v, ref product); } else { UInt128.Multiply(out product, ref b, (ulong)c); UInt128.Add(ref a.v, ref product); } } public static void SubtractProduct(ref Int128 a, ref UInt128 b, int c) { UInt128 d; if (c < 0) { UInt128.Multiply(out d, ref b, (uint)(-c)); UInt128.Add(ref a.v, ref d); } else { UInt128.Multiply(out d, ref b, (uint)c); UInt128.Subtract(ref a.v, ref d); } } public static void SubtractProduct(ref Int128 a, ref UInt128 b, long c) { UInt128 d; if (c < 0) { UInt128.Multiply(out d, ref b, (ulong)(-c)); UInt128.Add(ref a.v, ref d); } else { UInt128.Multiply(out d, ref b, (ulong)c); UInt128.Subtract(ref a.v, ref d); } } public static void AddProduct(ref Int128 a, UInt128 b, int c) { AddProduct(ref a, ref b, c); } public static void AddProduct(ref Int128 a, UInt128 b, long c) { AddProduct(ref a, ref b, c); } public static void SubtractProduct(ref Int128 a, UInt128 b, int c) { SubtractProduct(ref a, ref b, c); } public static void SubtractProduct(ref Int128 a, UInt128 b, long c) { SubtractProduct(ref a, ref b, c); } public static void Pow(out Int128 result, ref Int128 value, int exponent) { if (exponent < 0) throw new ArgumentException("exponent must not be negative"); if (value.IsNegative) { UInt128 valueneg; UInt128.Negate(out valueneg, ref value.v); if ((exponent & 1) == 0) UInt128.Pow(out result.v, ref valueneg, (uint)exponent); else { UInt128.Pow(out result.v, ref valueneg, (uint)exponent); UInt128.Negate(ref result.v); } } else UInt128.Pow(out result.v, ref value.v, (uint)exponent); } public static Int128 Pow(Int128 value, int exponent) { Int128 result; Pow(out result, ref value, exponent); return result; } public static ulong FloorSqrt(Int128 a) { if (a.IsNegative) throw new ArgumentException("argument must not be negative"); return UInt128.FloorSqrt(a.v); } public static ulong CeilingSqrt(Int128 a) { if (a.IsNegative) throw new ArgumentException("argument must not be negative"); return UInt128.CeilingSqrt(a.v); } public static long FloorCbrt(Int128 a) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); return -(long)UInt128.FloorCbrt(aneg); } return (long)UInt128.FloorCbrt(a.v); } public static long CeilingCbrt(Int128 a) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); return -(long)UInt128.CeilingCbrt(aneg); } return (long)UInt128.CeilingCbrt(a.v); } public static Int128 Min(Int128 a, Int128 b) { if (LessThan(ref a.v, ref b.v)) return a; return b; } public static Int128 Max(Int128 a, Int128 b) { if (LessThan(ref b.v, ref a.v)) return a; return b; } public static double Log(Int128 a) { return Log(a, Math.E); } public static double Log10(Int128 a) { return Log(a, 10); } public static double Log(Int128 a, double b) { if (a.IsNegative || a.IsZero) throw new ArgumentException("argument must be positive"); return Math.Log(UInt128.ConvertToDouble(ref a.v), b); } public static Int128 Add(Int128 a, Int128 b) { Int128 c; UInt128.Add(out c.v, ref a.v, ref b.v); return c; } public static Int128 Subtract(Int128 a, Int128 b) { Int128 c; UInt128.Subtract(out c.v, ref a.v, ref b.v); return c; } public static Int128 Multiply(Int128 a, Int128 b) { Int128 c; Multiply(out c, ref a, ref b); return c; } public static Int128 Divide(Int128 a, Int128 b) { Int128 c; Divide(out c, ref a, ref b); return c; } public static Int128 Remainder(Int128 a, Int128 b) { Int128 c; Remainder(out c, ref a, ref b); return c; } public static Int128 DivRem(Int128 a, Int128 b, out Int128 remainder) { Int128 c; Divide(out c, ref a, ref b); Remainder(out remainder, ref a, ref b); return c; } public static Int128 Negate(Int128 a) { Int128 c; UInt128.Negate(out c.v, ref a.v); return c; } public static Int128 GreatestCommonDivisor(Int128 a, Int128 b) { Int128 c; GreatestCommonDivisor(out c, ref a, ref b); return c; } public static void GreatestCommonDivisor(out Int128 c, ref Int128 a, ref Int128 b) { if (a.IsNegative) { UInt128 aneg; UInt128.Negate(out aneg, ref a.v); if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.GreatestCommonDivisor(out c.v, ref aneg, ref bneg); } else UInt128.GreatestCommonDivisor(out c.v, ref aneg, ref b.v); } else { if (b.IsNegative) { UInt128 bneg; UInt128.Negate(out bneg, ref b.v); UInt128.GreatestCommonDivisor(out c.v, ref a.v, ref bneg); } else UInt128.GreatestCommonDivisor(out c.v, ref a.v, ref b.v); } } public static void LeftShift(ref Int128 c, int d) { UInt128.LeftShift(ref c.v, d); } public static void LeftShift(ref Int128 c) { UInt128.LeftShift(ref c.v); } public static void RightShift(ref Int128 c, int d) { UInt128.ArithmeticRightShift(ref c.v, d); } public static void RightShift(ref Int128 c) { UInt128.ArithmeticRightShift(ref c.v); } public static void Swap(ref Int128 a, ref Int128 b) { UInt128.Swap(ref a.v, ref b.v); } public static int Compare(Int128 a, Int128 b) { return a.CompareTo(b); } public static void Shift(out Int128 c, ref Int128 a, int d) { UInt128.ArithmeticShift(out c.v, ref a.v, d); } public static void Shift(ref Int128 c, int d) { UInt128.ArithmeticShift(ref c.v, d); } public static Int128 ModAdd(Int128 a, Int128 b, Int128 modulus) { Int128 c; UInt128.ModAdd(out c.v, ref a.v, ref b.v, ref modulus.v); return c; } public static Int128 ModSub(Int128 a, Int128 b, Int128 modulus) { Int128 c; UInt128.ModSub(out c.v, ref a.v, ref b.v, ref modulus.v); return c; } public static Int128 ModMul(Int128 a, Int128 b, Int128 modulus) { Int128 c; UInt128.ModMul(out c.v, ref a.v, ref b.v, ref modulus.v); return c; } public static Int128 ModPow(Int128 value, Int128 exponent, Int128 modulus) { Int128 result; UInt128.ModPow(out result.v, ref value.v, ref exponent.v, ref modulus.v); return result; } } }