2639 lines
75 KiB
C#
2639 lines
75 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
|
|
namespace Dirichlet.Numerics
|
|
{
|
|
public struct UInt128 : IFormattable, IComparable, IComparable<UInt128>, IEquatable<UInt128>
|
|
{
|
|
private struct UInt256
|
|
{
|
|
public ulong s0;
|
|
public ulong s1;
|
|
public ulong s2;
|
|
public ulong s3;
|
|
|
|
public uint r0 { get { return (uint)s0; } }
|
|
public uint r1 { get { return (uint)(s0 >> 32); } }
|
|
public uint r2 { get { return (uint)s1; } }
|
|
public uint r3 { get { return (uint)(s1 >> 32); } }
|
|
public uint r4 { get { return (uint)s2; } }
|
|
public uint r5 { get { return (uint)(s2 >> 32); } }
|
|
public uint r6 { get { return (uint)s3; } }
|
|
public uint r7 { get { return (uint)(s3 >> 32); } }
|
|
|
|
public UInt128 t0 { get { UInt128 result; UInt128.Create(out result, s0, s1); return result; } }
|
|
public UInt128 t1 { get { UInt128 result; UInt128.Create(out result, s2, s3); return result; } }
|
|
|
|
public static implicit operator BigInteger(UInt256 a)
|
|
{
|
|
return (BigInteger)a.s3 << 192 | (BigInteger)a.s2 << 128 | (BigInteger)a.s1 << 64 | a.s0;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return ((BigInteger)this).ToString();
|
|
}
|
|
}
|
|
|
|
private ulong s0;
|
|
private ulong s1;
|
|
|
|
private static readonly UInt128 maxValue = ~(UInt128)0;
|
|
private static readonly UInt128 zero = (UInt128)0;
|
|
private static readonly UInt128 one = (UInt128)1;
|
|
|
|
public static UInt128 MinValue { get { return zero; } }
|
|
public static UInt128 MaxValue { get { return maxValue; } }
|
|
public static UInt128 Zero { get { return zero; } }
|
|
public static UInt128 One { get { return one; } }
|
|
|
|
public static UInt128 Parse(string value)
|
|
{
|
|
UInt128 c;
|
|
if (!TryParse(value, out c))
|
|
throw new FormatException();
|
|
return c;
|
|
}
|
|
|
|
public static bool TryParse(string value, out UInt128 result)
|
|
{
|
|
return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
|
|
}
|
|
|
|
public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out UInt128 result)
|
|
{
|
|
BigInteger a;
|
|
if (!BigInteger.TryParse(value, style, provider, out a))
|
|
{
|
|
result = Zero;
|
|
return false;
|
|
}
|
|
Create(out result, a);
|
|
return true;
|
|
}
|
|
|
|
public UInt128(long value)
|
|
{
|
|
Create(out this, value);
|
|
}
|
|
|
|
public UInt128(ulong value)
|
|
{
|
|
Create(out this, value);
|
|
}
|
|
|
|
public UInt128(decimal value)
|
|
{
|
|
Create(out this, value);
|
|
}
|
|
|
|
public UInt128(double value)
|
|
{
|
|
Create(out this, value);
|
|
}
|
|
|
|
public UInt128(BigInteger value)
|
|
{
|
|
Create(out this, value);
|
|
}
|
|
|
|
public static void Create(out UInt128 c, uint r0, uint r1, uint r2, uint r3)
|
|
{
|
|
c.s0 = (ulong)r1 << 32 | r0;
|
|
c.s1 = (ulong)r3 << 32 | r2;
|
|
}
|
|
|
|
public static void Create(out UInt128 c, ulong s0, ulong s1)
|
|
{
|
|
c.s0 = s0;
|
|
c.s1 = s1;
|
|
}
|
|
|
|
public static void Create(out UInt128 c, long a)
|
|
{
|
|
c.s0 = (ulong)a;
|
|
c.s1 = a < 0 ? ulong.MaxValue : 0;
|
|
}
|
|
|
|
public static void Create(out UInt128 c, ulong a)
|
|
{
|
|
c.s0 = a;
|
|
c.s1 = 0;
|
|
}
|
|
|
|
public static void Create(out UInt128 c, decimal a)
|
|
{
|
|
var bits = decimal.GetBits(decimal.Truncate(a));
|
|
Create(out c, (uint)bits[0], (uint)bits[1], (uint)bits[2], 0);
|
|
if (a < 0)
|
|
Negate(ref c);
|
|
}
|
|
|
|
public static void Create(out UInt128 c, BigInteger a)
|
|
{
|
|
var sign = a.Sign;
|
|
if (sign == -1)
|
|
a = -a;
|
|
c.s0 = (ulong)(a & ulong.MaxValue);
|
|
c.s1 = (ulong)(a >> 64);
|
|
if (sign == -1)
|
|
Negate(ref c);
|
|
}
|
|
|
|
public static void Create(out UInt128 c, double a)
|
|
{
|
|
var negate = false;
|
|
if (a < 0)
|
|
{
|
|
negate = true;
|
|
a = -a;
|
|
}
|
|
if (a <= ulong.MaxValue)
|
|
{
|
|
c.s0 = (ulong)a;
|
|
c.s1 = 0;
|
|
}
|
|
else
|
|
{
|
|
var shift = Math.Max((int)Math.Ceiling(Math.Log(a, 2)) - 63, 0);
|
|
c.s0 = (ulong)(a / Math.Pow(2, shift));
|
|
c.s1 = 0;
|
|
LeftShift(ref c, shift);
|
|
}
|
|
if (negate)
|
|
Negate(ref c);
|
|
}
|
|
|
|
private uint r0 { get { return (uint)s0; } }
|
|
private uint r1 { get { return (uint)(s0 >> 32); } }
|
|
private uint r2 { get { return (uint)s1; } }
|
|
private uint r3 { get { return (uint)(s1 >> 32); } }
|
|
|
|
public ulong S0 { get { return s0; } }
|
|
public ulong S1 { get { return s1; } }
|
|
|
|
public bool IsZero { get { return (s0 | s1) == 0; } }
|
|
public bool IsOne { get { return (s1 ^ s0) == 1; } }
|
|
public bool IsPowerOfTwo { get { return (this & (this - 1)).IsZero; } }
|
|
public bool IsEven { get { return (s0 & 1) == 0; } }
|
|
public int Sign { get { return IsZero ? 0 : 1; } }
|
|
|
|
public override string ToString()
|
|
{
|
|
return ((BigInteger)this).ToString("x");
|
|
}
|
|
|
|
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 UInt128(double a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(sbyte a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static implicit operator UInt128(byte a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(short a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static implicit operator UInt128(ushort a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(int a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static implicit operator UInt128(uint a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(long a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static implicit operator UInt128(ulong a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(decimal a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator UInt128(BigInteger a)
|
|
{
|
|
UInt128 c;
|
|
Create(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static explicit operator float(UInt128 a)
|
|
{
|
|
return ConvertToFloat(ref a);
|
|
}
|
|
|
|
public static explicit operator double(UInt128 a)
|
|
{
|
|
return ConvertToDouble(ref a);
|
|
}
|
|
|
|
public static float ConvertToFloat(ref UInt128 a)
|
|
{
|
|
if (a.s1 == 0)
|
|
return a.s0;
|
|
return a.s1 * (float)ulong.MaxValue + a.s0;
|
|
}
|
|
|
|
public static double ConvertToDouble(ref UInt128 a)
|
|
{
|
|
if (a.s1 == 0)
|
|
return a.s0;
|
|
return a.s1 * (double)ulong.MaxValue + a.s0;
|
|
}
|
|
|
|
public static explicit operator sbyte(UInt128 a)
|
|
{
|
|
return (sbyte)a.s0;
|
|
}
|
|
|
|
public static explicit operator byte(UInt128 a)
|
|
{
|
|
return (byte)a.s0;
|
|
}
|
|
|
|
public static explicit operator short(UInt128 a)
|
|
{
|
|
return (short)a.s0;
|
|
}
|
|
|
|
public static explicit operator ushort(UInt128 a)
|
|
{
|
|
return (ushort)a.s0;
|
|
}
|
|
|
|
public static explicit operator int(UInt128 a)
|
|
{
|
|
return (int)a.s0;
|
|
}
|
|
|
|
public static explicit operator uint(UInt128 a)
|
|
{
|
|
return (uint)a.s0;
|
|
}
|
|
|
|
public static explicit operator long(UInt128 a)
|
|
{
|
|
return (long)a.s0;
|
|
}
|
|
|
|
public static explicit operator ulong(UInt128 a)
|
|
{
|
|
return a.s0;
|
|
}
|
|
|
|
public static explicit operator decimal(UInt128 a)
|
|
{
|
|
if (a.s1 == 0)
|
|
return a.s0;
|
|
var shift = Math.Max(0, 32 - GetBitLength(a.s1));
|
|
UInt128 ashift;
|
|
RightShift(out ashift, ref a, shift);
|
|
return new decimal((int)a.r0, (int)a.r1, (int)a.r2, false, (byte)shift);
|
|
}
|
|
|
|
public static implicit operator BigInteger(UInt128 a)
|
|
{
|
|
if (a.s1 == 0)
|
|
return a.s0;
|
|
return (BigInteger)a.s1 << 64 | a.s0;
|
|
}
|
|
|
|
public static UInt128 operator <<(UInt128 a, int b)
|
|
{
|
|
UInt128 c;
|
|
LeftShift(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator >>(UInt128 a, int b)
|
|
{
|
|
UInt128 c;
|
|
RightShift(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator &(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
And(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static uint operator &(UInt128 a, uint b)
|
|
{
|
|
return (uint)a.s0 & b;
|
|
}
|
|
|
|
public static uint operator &(uint a, UInt128 b)
|
|
{
|
|
return a & (uint)b.s0;
|
|
}
|
|
|
|
public static ulong operator &(UInt128 a, ulong b)
|
|
{
|
|
return a.s0 & b;
|
|
}
|
|
|
|
public static ulong operator &(ulong a, UInt128 b)
|
|
{
|
|
return a & b.s0;
|
|
}
|
|
|
|
public static UInt128 operator |(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Or(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator ^(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
ExclusiveOr(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator ~(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Not(out c, ref a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator +(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Add(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator +(UInt128 a, ulong b)
|
|
{
|
|
UInt128 c;
|
|
Add(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator +(ulong a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Add(out c, ref b, a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator ++(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Add(out c, ref a, 1);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator -(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Subtract(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator -(UInt128 a, ulong b)
|
|
{
|
|
UInt128 c;
|
|
Subtract(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator -(ulong a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Subtract(out c, a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator --(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Subtract(out c, ref a, 1);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator +(UInt128 a)
|
|
{
|
|
return a;
|
|
}
|
|
|
|
public static UInt128 operator *(UInt128 a, uint b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator *(uint a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref b, a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator *(UInt128 a, ulong b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator *(ulong a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref b, a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator *(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator /(UInt128 a, ulong b)
|
|
{
|
|
UInt128 c;
|
|
Divide(out c, ref a, b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 operator /(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Divide(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static ulong operator %(UInt128 a, uint b)
|
|
{
|
|
return Remainder(ref a, b);
|
|
}
|
|
|
|
public static ulong operator %(UInt128 a, ulong b)
|
|
{
|
|
return Remainder(ref a, b);
|
|
}
|
|
|
|
public static UInt128 operator %(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Remainder(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static bool operator <(UInt128 a, UInt128 b)
|
|
{
|
|
return LessThan(ref a, ref b);
|
|
}
|
|
|
|
public static bool operator <(UInt128 a, int b)
|
|
{
|
|
return LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator <(int a, UInt128 b)
|
|
{
|
|
return LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator <(UInt128 a, uint b)
|
|
{
|
|
return LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator <(uint a, UInt128 b)
|
|
{
|
|
return LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator <(UInt128 a, long b)
|
|
{
|
|
return LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator <(long a, UInt128 b)
|
|
{
|
|
return LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator <(UInt128 a, ulong b)
|
|
{
|
|
return LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator <(ulong a, UInt128 b)
|
|
{
|
|
return LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator <=(UInt128 a, UInt128 b)
|
|
{
|
|
return !LessThan(ref b, ref a);
|
|
}
|
|
|
|
public static bool operator <=(UInt128 a, int b)
|
|
{
|
|
return !LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator <=(int a, UInt128 b)
|
|
{
|
|
return !LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator <=(UInt128 a, uint b)
|
|
{
|
|
return !LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator <=(uint a, UInt128 b)
|
|
{
|
|
return !LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator <=(UInt128 a, long b)
|
|
{
|
|
return !LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator <=(long a, UInt128 b)
|
|
{
|
|
return !LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator <=(UInt128 a, ulong b)
|
|
{
|
|
return !LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator <=(ulong a, UInt128 b)
|
|
{
|
|
return !LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator >(UInt128 a, UInt128 b)
|
|
{
|
|
return LessThan(ref b, ref a);
|
|
}
|
|
|
|
public static bool operator >(UInt128 a, int b)
|
|
{
|
|
return LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator >(int a, UInt128 b)
|
|
{
|
|
return LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator >(UInt128 a, uint b)
|
|
{
|
|
return LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator >(uint a, UInt128 b)
|
|
{
|
|
return LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator >(UInt128 a, long b)
|
|
{
|
|
return LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator >(long a, UInt128 b)
|
|
{
|
|
return LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator >(UInt128 a, ulong b)
|
|
{
|
|
return LessThan(b, ref a);
|
|
}
|
|
|
|
public static bool operator >(ulong a, UInt128 b)
|
|
{
|
|
return LessThan(ref b, a);
|
|
}
|
|
|
|
public static bool operator >=(UInt128 a, UInt128 b)
|
|
{
|
|
return !LessThan(ref a, ref b);
|
|
}
|
|
|
|
public static bool operator >=(UInt128 a, int b)
|
|
{
|
|
return !LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator >=(int a, UInt128 b)
|
|
{
|
|
return !LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator >=(UInt128 a, uint b)
|
|
{
|
|
return !LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator >=(uint a, UInt128 b)
|
|
{
|
|
return !LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator >=(UInt128 a, long b)
|
|
{
|
|
return !LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator >=(long a, UInt128 b)
|
|
{
|
|
return !LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator >=(UInt128 a, ulong b)
|
|
{
|
|
return !LessThan(ref a, b);
|
|
}
|
|
|
|
public static bool operator >=(ulong a, UInt128 b)
|
|
{
|
|
return !LessThan(a, ref b);
|
|
}
|
|
|
|
public static bool operator ==(UInt128 a, UInt128 b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator ==(UInt128 a, int b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator ==(int a, UInt128 b)
|
|
{
|
|
return b.Equals(a);
|
|
}
|
|
|
|
public static bool operator ==(UInt128 a, uint b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator ==(uint a, UInt128 b)
|
|
{
|
|
return b.Equals(a);
|
|
}
|
|
|
|
public static bool operator ==(UInt128 a, long b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator ==(long a, UInt128 b)
|
|
{
|
|
return b.Equals(a);
|
|
}
|
|
|
|
public static bool operator ==(UInt128 a, ulong b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator ==(ulong a, UInt128 b)
|
|
{
|
|
return b.Equals(a);
|
|
}
|
|
|
|
public static bool operator !=(UInt128 a, UInt128 b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(UInt128 a, int b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(int a, UInt128 b)
|
|
{
|
|
return !b.Equals(a);
|
|
}
|
|
|
|
public static bool operator !=(UInt128 a, uint b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(uint a, UInt128 b)
|
|
{
|
|
return !b.Equals(a);
|
|
}
|
|
|
|
public static bool operator !=(UInt128 a, long b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(long a, UInt128 b)
|
|
{
|
|
return !b.Equals(a);
|
|
}
|
|
|
|
public static bool operator !=(UInt128 a, ulong b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(ulong a, UInt128 b)
|
|
{
|
|
return !b.Equals(a);
|
|
}
|
|
|
|
public int CompareTo(UInt128 other)
|
|
{
|
|
if (s1 != other.s1)
|
|
return s1.CompareTo(other.s1);
|
|
return s0.CompareTo(other.s0);
|
|
}
|
|
|
|
public int CompareTo(int other)
|
|
{
|
|
if (s1 != 0 || other < 0)
|
|
return 1;
|
|
return s0.CompareTo((ulong)other);
|
|
}
|
|
|
|
public int CompareTo(uint other)
|
|
{
|
|
if (s1 != 0)
|
|
return 1;
|
|
return s0.CompareTo((ulong)other);
|
|
}
|
|
|
|
public int CompareTo(long other)
|
|
{
|
|
if (s1 != 0 || other < 0)
|
|
return 1;
|
|
return s0.CompareTo((ulong)other);
|
|
}
|
|
|
|
public int CompareTo(ulong other)
|
|
{
|
|
if (s1 != 0)
|
|
return 1;
|
|
return s0.CompareTo(other);
|
|
}
|
|
|
|
public int CompareTo(object obj)
|
|
{
|
|
if (obj == null)
|
|
return 1;
|
|
if (!(obj is UInt128))
|
|
throw new ArgumentException();
|
|
return CompareTo((UInt128)obj);
|
|
}
|
|
|
|
private static bool LessThan(ref UInt128 a, long b)
|
|
{
|
|
return b >= 0 && a.s1 == 0 && a.s0 < (ulong)b;
|
|
}
|
|
|
|
private static bool LessThan(long a, ref UInt128 b)
|
|
{
|
|
return a < 0 || b.s1 != 0 || (ulong)a < b.s0;
|
|
}
|
|
|
|
private static bool LessThan(ref UInt128 a, ulong b)
|
|
{
|
|
return a.s1 == 0 && a.s0 < b;
|
|
}
|
|
|
|
private static bool LessThan(ulong a, ref UInt128 b)
|
|
{
|
|
return b.s1 != 0 || a < b.s0;
|
|
}
|
|
|
|
private static bool LessThan(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
if (a.s1 != b.s1)
|
|
return a.s1 < b.s1;
|
|
return a.s0 < b.s0;
|
|
}
|
|
|
|
public static bool Equals(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
return a.s0 == b.s0 && a.s1 == b.s1;
|
|
}
|
|
|
|
public bool Equals(UInt128 other)
|
|
{
|
|
return s0 == other.s0 && s1 == other.s1;
|
|
}
|
|
|
|
public bool Equals(int other)
|
|
{
|
|
return other >= 0 && s0 == (uint)other && s1 == 0;
|
|
}
|
|
|
|
public bool Equals(uint other)
|
|
{
|
|
return s0 == other && s1 == 0;
|
|
}
|
|
|
|
public bool Equals(long other)
|
|
{
|
|
return other >= 0 && s0 == (ulong)other && s1 == 0;
|
|
}
|
|
|
|
public bool Equals(ulong other)
|
|
{
|
|
return s0 == other && s1 == 0;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (!(obj is UInt128))
|
|
return false;
|
|
return Equals((UInt128)obj);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return s0.GetHashCode() ^ s1.GetHashCode();
|
|
}
|
|
|
|
public static void Multiply(out UInt128 c, ulong a, ulong b)
|
|
{
|
|
Multiply64(out c, a, b);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b);
|
|
}
|
|
|
|
public static void Multiply(out UInt128 c, ref UInt128 a, uint b)
|
|
{
|
|
if (a.s1 == 0)
|
|
Multiply64(out c, a.s0, b);
|
|
else
|
|
Multiply128(out c, ref a, b);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Multiply(out UInt128 c, ref UInt128 a, ulong b)
|
|
{
|
|
if (a.s1 == 0)
|
|
Multiply64(out c, a.s0, b);
|
|
else
|
|
Multiply128(out c, ref a, b);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Multiply(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
if ((a.s1 | b.s1) == 0)
|
|
Multiply64(out c, a.s0, b.s0);
|
|
else if (a.s1 == 0)
|
|
Multiply128(out c, ref b, a.s0);
|
|
else if (b.s1 == 0)
|
|
Multiply128(out c, ref a, b.s0);
|
|
else
|
|
Multiply128(out c, ref a, ref b);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
private static void Multiply(out UInt256 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
#if true
|
|
UInt128 c00, c01, c10, c11;
|
|
Multiply64(out c00, a.s0, b.s0);
|
|
Multiply64(out c01, a.s0, b.s1);
|
|
Multiply64(out c10, a.s1, b.s0);
|
|
Multiply64(out c11, a.s1, b.s1);
|
|
var carry1 = (uint)0;
|
|
var carry2 = (uint)0;
|
|
c.s0 = c00.S0;
|
|
c.s1 = Add(Add(c00.s1, c01.s0, ref carry1), c10.s0, ref carry1);
|
|
c.s2 = Add(Add(Add(c01.s1, c10.s1, ref carry2), c11.s0, ref carry2), carry1, ref carry2);
|
|
c.s3 = c11.s1 + carry2;
|
|
#else
|
|
// Karatsuba method.
|
|
// Warning: doesn't correctly handle overflow.
|
|
UInt128 z0, z1, z2;
|
|
Multiply64(out z0, a.s0, b.s0);
|
|
Multiply64(out z2, a.s1, b.s1);
|
|
Multiply64(out z1, a.s0 + a.s1, b.s0 + b.s1);
|
|
Subtract(ref z1, ref z2);
|
|
Subtract(ref z1, ref z0);
|
|
var carry1 = (uint)0;
|
|
var carry2 = (uint)0;
|
|
c.s0 = z0.S0;
|
|
c.s1 = Add(z0.s1, z1.s0, ref carry1);
|
|
c.s2 = Add(Add(z1.s1, z2.s0, ref carry2), carry1, ref carry2);
|
|
c.s3 = z2.s1 + carry2;
|
|
#endif
|
|
Debug.Assert((BigInteger)c == (BigInteger)a * (BigInteger)b);
|
|
}
|
|
|
|
public static UInt128 Abs(UInt128 a)
|
|
{
|
|
return a;
|
|
}
|
|
|
|
public static UInt128 Square(ulong a)
|
|
{
|
|
UInt128 c;
|
|
Square(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Square(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Square(out c, ref a);
|
|
return c;
|
|
}
|
|
|
|
public static void Square(out UInt128 c, ulong a)
|
|
{
|
|
Square64(out c, a);
|
|
}
|
|
|
|
public static void Square(out UInt128 c, ref UInt128 a)
|
|
{
|
|
if (a.s1 == 0)
|
|
Square64(out c, a.s0);
|
|
else
|
|
Multiply128(out c, ref a, ref a);
|
|
}
|
|
|
|
public static UInt128 Cube(ulong a)
|
|
{
|
|
UInt128 c;
|
|
Cube(out c, a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Cube(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Cube(out c, ref a);
|
|
return c;
|
|
}
|
|
|
|
public static void Cube(out UInt128 c, ulong a)
|
|
{
|
|
UInt128 square;
|
|
Square(out square, a);
|
|
Multiply(out c, ref square, a);
|
|
}
|
|
|
|
public static void Cube(out UInt128 c, ref UInt128 a)
|
|
{
|
|
UInt128 square;
|
|
if (a.s1 == 0)
|
|
{
|
|
Square64(out square, a.s0);
|
|
Multiply(out c, ref square, a.s0);
|
|
}
|
|
else
|
|
{
|
|
Multiply128(out square, ref a, ref a);
|
|
Multiply128(out c, ref square, ref a);
|
|
}
|
|
}
|
|
|
|
public static void Add(out UInt128 c, ulong a, ulong b)
|
|
{
|
|
c.s0 = a + b;
|
|
c.s1 = 0;
|
|
if (c.s0 < a && c.s0 < b)
|
|
++c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a + (BigInteger)b));
|
|
}
|
|
|
|
public static void Add(out UInt128 c, ref UInt128 a, ulong b)
|
|
{
|
|
c.s0 = a.s0 + b;
|
|
c.s1 = a.s1;
|
|
if (c.s0 < a.s0 && c.s0 < b)
|
|
++c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a + (BigInteger)b) % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Add(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
c.s0 = a.s0 + b.s0;
|
|
c.s1 = a.s1 + b.s1;
|
|
if (c.s0 < a.s0 && c.s0 < b.s0)
|
|
++c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a + (BigInteger)b) % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
private static ulong Add(ulong a, ulong b, ref uint carry)
|
|
{
|
|
var c = a + b;
|
|
if (c < a && c < b)
|
|
++carry;
|
|
return c;
|
|
}
|
|
|
|
public static void Add(ref UInt128 a, ulong b)
|
|
{
|
|
var sum = a.s0 + b;
|
|
if (sum < a.s0 && sum < b)
|
|
++a.s1;
|
|
a.s0 = sum;
|
|
}
|
|
|
|
public static void Add(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
var sum = a.s0 + b.s0;
|
|
if (sum < a.s0 && sum < b.s0)
|
|
++a.s1;
|
|
a.s0 = sum;
|
|
a.s1 += b.s1;
|
|
}
|
|
|
|
public static void Add(ref UInt128 a, UInt128 b)
|
|
{
|
|
Add(ref a, ref b);
|
|
}
|
|
|
|
public static void Subtract(out UInt128 c, ref UInt128 a, ulong b)
|
|
{
|
|
c.s0 = a.s0 - b;
|
|
c.s1 = a.s1;
|
|
if (a.s0 < b)
|
|
--c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a - (BigInteger)b + ((BigInteger)1 << 128)) % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Subtract(out UInt128 c, ulong a, ref UInt128 b)
|
|
{
|
|
c.s0 = a - b.s0;
|
|
c.s1 = 0 - b.s1;
|
|
if (a < b.s0)
|
|
--c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a - (BigInteger)b + ((BigInteger)1 << 128)) % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Subtract(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
c.s0 = a.s0 - b.s0;
|
|
c.s1 = a.s1 - b.s1;
|
|
if (a.s0 < b.s0)
|
|
--c.s1;
|
|
Debug.Assert((BigInteger)c == ((BigInteger)a - (BigInteger)b + ((BigInteger)1 << 128)) % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Subtract(ref UInt128 a, ulong b)
|
|
{
|
|
if (a.s0 < b)
|
|
--a.s1;
|
|
a.s0 -= b;
|
|
}
|
|
|
|
public static void Subtract(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
if (a.s0 < b.s0)
|
|
--a.s1;
|
|
a.s0 -= b.s0;
|
|
a.s1 -= b.s1;
|
|
}
|
|
|
|
public static void Subtract(ref UInt128 a, UInt128 b)
|
|
{
|
|
Subtract(ref a, ref b);
|
|
}
|
|
|
|
private static void Square64(out UInt128 w, ulong u)
|
|
{
|
|
var u0 = (ulong)(uint)u;
|
|
var u1 = u >> 32;
|
|
var carry = u0 * u0;
|
|
var r0 = (uint)carry;
|
|
var u0u1 = u0 * u1;
|
|
carry = (carry >> 32) + u0u1;
|
|
var r2 = carry >> 32;
|
|
carry = (uint)carry + u0u1;
|
|
w.s0 = carry << 32 | r0;
|
|
w.s1 = (carry >> 32) + r2 + u1 * u1;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * u);
|
|
}
|
|
|
|
private static void Multiply64(out UInt128 w, uint u, uint v)
|
|
{
|
|
w.s0 = (ulong)u * v;
|
|
w.s1 = 0;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v);
|
|
}
|
|
|
|
private static void Multiply64(out UInt128 w, ulong u, uint v)
|
|
{
|
|
var u0 = (ulong)(uint)u;
|
|
var u1 = u >> 32;
|
|
var carry = u0 * v;
|
|
var r0 = (uint)carry;
|
|
carry = (carry >> 32) + u1 * v;
|
|
w.s0 = carry << 32 | r0;
|
|
w.s1 = carry >> 32;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v);
|
|
}
|
|
|
|
private static void Multiply64(out UInt128 w, ulong u, ulong v)
|
|
{
|
|
var u0 = (ulong)(uint)u;
|
|
var u1 = u >> 32;
|
|
var v0 = (ulong)(uint)v;
|
|
var v1 = v >> 32;
|
|
var carry = u0 * v0;
|
|
var r0 = (uint)carry;
|
|
carry = (carry >> 32) + u0 * v1;
|
|
var r2 = carry >> 32;
|
|
carry = (uint)carry + u1 * v0;
|
|
w.s0 = carry << 32 | r0;
|
|
w.s1 = (carry >> 32) + r2 + u1 * v1;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v);
|
|
}
|
|
|
|
private static void Multiply64(out UInt128 w, ulong u, ulong v, ulong c)
|
|
{
|
|
var u0 = (ulong)(uint)u;
|
|
var u1 = u >> 32;
|
|
var v0 = (ulong)(uint)v;
|
|
var v1 = v >> 32;
|
|
var carry = u0 * v0 + (uint)c;
|
|
var r0 = (uint)carry;
|
|
carry = (carry >> 32) + u0 * v1 + (c >> 32);
|
|
var r2 = carry >> 32;
|
|
carry = (uint)carry + u1 * v0;
|
|
w.s0 = carry << 32 | r0;
|
|
w.s1 = (carry >> 32) + r2 + u1 * v1;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v + c);
|
|
}
|
|
|
|
private static ulong MultiplyHigh64(ulong u, ulong v, ulong c)
|
|
{
|
|
var u0 = (ulong)(uint)u;
|
|
var u1 = u >> 32;
|
|
var v0 = (ulong)(uint)v;
|
|
var v1 = v >> 32;
|
|
var carry = ((u0 * v0 + (uint)c) >> 32) + u0 * v1 + (c >> 32);
|
|
var r2 = carry >> 32;
|
|
carry = (uint)carry + u1 * v0;
|
|
return (carry >> 32) + r2 + u1 * v1;
|
|
}
|
|
|
|
private static void Multiply128(out UInt128 w, ref UInt128 u, uint v)
|
|
{
|
|
Multiply64(out w, u.s0, v);
|
|
w.s1 += u.s1 * v;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
private static void Multiply128(out UInt128 w, ref UInt128 u, ulong v)
|
|
{
|
|
Multiply64(out w, u.s0, v);
|
|
w.s1 += u.s1 * v;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
private static void Multiply128(out UInt128 w, ref UInt128 u, ref UInt128 v)
|
|
{
|
|
Multiply64(out w, u.s0, v.s0);
|
|
w.s1 += u.s1 * v.s0 + u.s0 * v.s1;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u * v % ((BigInteger)1 << 128));
|
|
}
|
|
|
|
public static void Divide(out UInt128 w, ref UInt128 u, uint v)
|
|
{
|
|
if (u.s1 == 0)
|
|
Divide64(out w, u.s0, v);
|
|
else if (u.s1 <= uint.MaxValue)
|
|
Divide96(out w, ref u, v);
|
|
else
|
|
Divide128(out w, ref u, v);
|
|
}
|
|
|
|
public static void Divide(out UInt128 w, ref UInt128 u, ulong v)
|
|
{
|
|
if (u.s1 == 0)
|
|
Divide64(out w, u.s0, v);
|
|
else
|
|
{
|
|
var v0 = (uint)v;
|
|
if (v == v0)
|
|
{
|
|
if (u.s1 <= uint.MaxValue)
|
|
Divide96(out w, ref u, v0);
|
|
else
|
|
Divide128(out w, ref u, v0);
|
|
}
|
|
else
|
|
{
|
|
if (u.s1 <= uint.MaxValue)
|
|
Divide96(out w, ref u, v);
|
|
else
|
|
Divide128(out w, ref u, v);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Divide(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
if (LessThan(ref a, ref b))
|
|
c = Zero;
|
|
else if (b.s1 == 0)
|
|
Divide(out c, ref a, b.s0);
|
|
else if (b.s1 <= uint.MaxValue)
|
|
{
|
|
UInt128 rem;
|
|
Create(out c, DivRem96(out rem, ref a, ref b));
|
|
}
|
|
else
|
|
{
|
|
UInt128 rem;
|
|
Create(out c, DivRem128(out rem, ref a, ref b));
|
|
}
|
|
}
|
|
|
|
public static uint Remainder(ref UInt128 u, uint v)
|
|
{
|
|
if (u.s1 == 0)
|
|
return (uint)(u.s0 % v);
|
|
if (u.s1 <= uint.MaxValue)
|
|
return Remainder96(ref u, v);
|
|
return Remainder128(ref u, v);
|
|
}
|
|
|
|
public static ulong Remainder(ref UInt128 u, ulong v)
|
|
{
|
|
if (u.s1 == 0)
|
|
return u.s0 % v;
|
|
var v0 = (uint)v;
|
|
if (v == v0)
|
|
{
|
|
if (u.s1 <= uint.MaxValue)
|
|
return Remainder96(ref u, v0);
|
|
return Remainder128(ref u, v0);
|
|
}
|
|
if (u.s1 <= uint.MaxValue)
|
|
return Remainder96(ref u, v);
|
|
return Remainder128(ref u, v);
|
|
}
|
|
|
|
public static void Remainder(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
if (LessThan(ref a, ref b))
|
|
c = a;
|
|
else if (b.s1 == 0)
|
|
Create(out c, Remainder(ref a, b.s0));
|
|
else if (b.s1 <= uint.MaxValue)
|
|
DivRem96(out c, ref a, ref b);
|
|
else
|
|
DivRem128(out c, ref a, ref b);
|
|
}
|
|
|
|
public static void Remainder(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
UInt128 a2 = a;
|
|
Remainder(out a, ref a2, ref b);
|
|
}
|
|
|
|
private static void Remainder(out UInt128 c, ref UInt256 a, ref UInt128 b)
|
|
{
|
|
if (b.r3 == 0)
|
|
Remainder192(out c, ref a, ref b);
|
|
else
|
|
Remainder256(out c, ref a, ref b);
|
|
}
|
|
|
|
private static void Divide64(out UInt128 w, ulong u, ulong v)
|
|
{
|
|
w.s1 = 0;
|
|
w.s0 = u / v;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u / v);
|
|
}
|
|
|
|
private static void Divide96(out UInt128 w, ref UInt128 u, uint v)
|
|
{
|
|
var r2 = u.r2;
|
|
var w2 = r2 / v;
|
|
var u0 = (ulong)(r2 - w2 * v);
|
|
var u0u1 = u0 << 32 | u.r1;
|
|
var w1 = (uint)(u0u1 / v);
|
|
u0 = u0u1 - w1 * v;
|
|
u0u1 = u0 << 32 | u.r0;
|
|
var w0 = (uint)(u0u1 / v);
|
|
w.s1 = w2;
|
|
w.s0 = (ulong)w1 << 32 | w0;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u / v);
|
|
}
|
|
|
|
private static void Divide128(out UInt128 w, ref UInt128 u, uint v)
|
|
{
|
|
var r3 = u.r3;
|
|
var w3 = r3 / v;
|
|
var u0 = (ulong)(r3 - w3 * v);
|
|
var u0u1 = u0 << 32 | u.r2;
|
|
var w2 = (uint)(u0u1 / v);
|
|
u0 = u0u1 - w2 * v;
|
|
u0u1 = u0 << 32 | u.r1;
|
|
var w1 = (uint)(u0u1 / v);
|
|
u0 = u0u1 - w1 * v;
|
|
u0u1 = u0 << 32 | u.r0;
|
|
var w0 = (uint)(u0u1 / v);
|
|
w.s1 = (ulong)w3 << 32 | w2;
|
|
w.s0 = (ulong)w1 << 32 | w0;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u / v);
|
|
}
|
|
|
|
private static void Divide96(out UInt128 w, ref UInt128 u, ulong v)
|
|
{
|
|
w.s0 = w.s1 = 0;
|
|
var dneg = GetBitLength((uint)(v >> 32));
|
|
var d = 32 - dneg;
|
|
var vPrime = v << d;
|
|
var v1 = (uint)(vPrime >> 32);
|
|
var v2 = (uint)vPrime;
|
|
var r0 = u.r0;
|
|
var r1 = u.r1;
|
|
var r2 = u.r2;
|
|
var r3 = (uint)0;
|
|
if (d != 0)
|
|
{
|
|
r3 = r2 >> dneg;
|
|
r2 = r2 << d | r1 >> dneg;
|
|
r1 = r1 << d | r0 >> dneg;
|
|
r0 <<= d;
|
|
}
|
|
var q1 = DivRem(r3, ref r2, ref r1, v1, v2);
|
|
var q0 = DivRem(r2, ref r1, ref r0, v1, v2);
|
|
w.s0 = (ulong)q1 << 32 | q0;
|
|
w.s1 = 0;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u / v);
|
|
}
|
|
|
|
private static void Divide128(out UInt128 w, ref UInt128 u, ulong v)
|
|
{
|
|
w.s0 = w.s1 = 0;
|
|
var dneg = GetBitLength((uint)(v >> 32));
|
|
var d = 32 - dneg;
|
|
var vPrime = v << d;
|
|
var v1 = (uint)(vPrime >> 32);
|
|
var v2 = (uint)vPrime;
|
|
var r0 = u.r0;
|
|
var r1 = u.r1;
|
|
var r2 = u.r2;
|
|
var r3 = u.r3;
|
|
var r4 = (uint)0;
|
|
if (d != 0)
|
|
{
|
|
r4 = r3 >> dneg;
|
|
r3 = r3 << d | r2 >> dneg;
|
|
r2 = r2 << d | r1 >> dneg;
|
|
r1 = r1 << d | r0 >> dneg;
|
|
r0 <<= d;
|
|
}
|
|
w.s1 = DivRem(r4, ref r3, ref r2, v1, v2);
|
|
var q1 = DivRem(r3, ref r2, ref r1, v1, v2);
|
|
var q0 = DivRem(r2, ref r1, ref r0, v1, v2);
|
|
w.s0 = (ulong)q1 << 32 | q0;
|
|
Debug.Assert((BigInteger)w == (BigInteger)u / v);
|
|
}
|
|
|
|
private static uint Remainder96(ref UInt128 u, uint v)
|
|
{
|
|
var u0 = (ulong)(u.r2 % v);
|
|
var u0u1 = u0 << 32 | u.r1;
|
|
u0 = u0u1 % v;
|
|
u0u1 = u0 << 32 | u.r0;
|
|
return (uint)(u0u1 % v);
|
|
}
|
|
|
|
private static uint Remainder128(ref UInt128 u, uint v)
|
|
{
|
|
var u0 = (ulong)(u.r3 % v);
|
|
var u0u1 = u0 << 32 | u.r2;
|
|
u0 = u0u1 % v;
|
|
u0u1 = u0 << 32 | u.r1;
|
|
u0 = u0u1 % v;
|
|
u0u1 = u0 << 32 | u.r0;
|
|
return (uint)(u0u1 % v);
|
|
}
|
|
|
|
private static ulong Remainder96(ref UInt128 u, ulong v)
|
|
{
|
|
var dneg = GetBitLength((uint)(v >> 32));
|
|
var d = 32 - dneg;
|
|
var vPrime = v << d;
|
|
var v1 = (uint)(vPrime >> 32);
|
|
var v2 = (uint)vPrime;
|
|
var r0 = u.r0;
|
|
var r1 = u.r1;
|
|
var r2 = u.r2;
|
|
var r3 = (uint)0;
|
|
if (d != 0)
|
|
{
|
|
r3 = r2 >> dneg;
|
|
r2 = r2 << d | r1 >> dneg;
|
|
r1 = r1 << d | r0 >> dneg;
|
|
r0 <<= d;
|
|
}
|
|
DivRem(r3, ref r2, ref r1, v1, v2);
|
|
DivRem(r2, ref r1, ref r0, v1, v2);
|
|
return ((ulong)r1 << 32 | r0) >> d;
|
|
}
|
|
|
|
private static ulong Remainder128(ref UInt128 u, ulong v)
|
|
{
|
|
var dneg = GetBitLength((uint)(v >> 32));
|
|
var d = 32 - dneg;
|
|
var vPrime = v << d;
|
|
var v1 = (uint)(vPrime >> 32);
|
|
var v2 = (uint)vPrime;
|
|
var r0 = u.r0;
|
|
var r1 = u.r1;
|
|
var r2 = u.r2;
|
|
var r3 = u.r3;
|
|
var r4 = (uint)0;
|
|
if (d != 0)
|
|
{
|
|
r4 = r3 >> dneg;
|
|
r3 = r3 << d | r2 >> dneg;
|
|
r2 = r2 << d | r1 >> dneg;
|
|
r1 = r1 << d | r0 >> dneg;
|
|
r0 <<= d;
|
|
}
|
|
DivRem(r4, ref r3, ref r2, v1, v2);
|
|
DivRem(r3, ref r2, ref r1, v1, v2);
|
|
DivRem(r2, ref r1, ref r0, v1, v2);
|
|
return ((ulong)r1 << 32 | r0) >> d;
|
|
}
|
|
|
|
private static ulong DivRem96(out UInt128 rem, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
var d = 32 - GetBitLength(b.r2);
|
|
UInt128 v;
|
|
LeftShift64(out v, ref b, d);
|
|
var r4 = (uint)LeftShift64(out rem, ref a, d);
|
|
var v1 = v.r2;
|
|
var v2 = v.r1;
|
|
var v3 = v.r0;
|
|
var r3 = rem.r3;
|
|
var r2 = rem.r2;
|
|
var r1 = rem.r1;
|
|
var r0 = rem.r0;
|
|
var q1 = DivRem(r4, ref r3, ref r2, ref r1, v1, v2, v3);
|
|
var q0 = DivRem(r3, ref r2, ref r1, ref r0, v1, v2, v3);
|
|
Create(out rem, r0, r1, r2, 0);
|
|
var div = (ulong)q1 << 32 | q0;
|
|
RightShift64(ref rem, d);
|
|
Debug.Assert((BigInteger)div == (BigInteger)a / (BigInteger)b);
|
|
Debug.Assert((BigInteger)rem == (BigInteger)a % (BigInteger)b);
|
|
return div;
|
|
}
|
|
|
|
private static uint DivRem128(out UInt128 rem, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
var d = 32 - GetBitLength(b.r3);
|
|
UInt128 v;
|
|
LeftShift64(out v, ref b, d);
|
|
var r4 = (uint)LeftShift64(out rem, ref a, d);
|
|
var r3 = rem.r3;
|
|
var r2 = rem.r2;
|
|
var r1 = rem.r1;
|
|
var r0 = rem.r0;
|
|
var div = DivRem(r4, ref r3, ref r2, ref r1, ref r0, v.r3, v.r2, v.r1, v.r0);
|
|
Create(out rem, r0, r1, r2, r3);
|
|
RightShift64(ref rem, d);
|
|
Debug.Assert((BigInteger)div == (BigInteger)a / (BigInteger)b);
|
|
Debug.Assert((BigInteger)rem == (BigInteger)a % (BigInteger)b);
|
|
return div;
|
|
}
|
|
|
|
private static void Remainder192(out UInt128 c, ref UInt256 a, ref UInt128 b)
|
|
{
|
|
var d = 32 - GetBitLength(b.r2);
|
|
UInt128 v;
|
|
LeftShift64(out v, ref b, d);
|
|
var v1 = v.r2;
|
|
var v2 = v.r1;
|
|
var v3 = v.r0;
|
|
UInt256 rem;
|
|
LeftShift64(out rem, ref a, d);
|
|
var r6 = rem.r6;
|
|
var r5 = rem.r5;
|
|
var r4 = rem.r4;
|
|
var r3 = rem.r3;
|
|
var r2 = rem.r2;
|
|
var r1 = rem.r1;
|
|
var r0 = rem.r0;
|
|
DivRem(r6, ref r5, ref r4, ref r3, v1, v2, v3);
|
|
DivRem(r5, ref r4, ref r3, ref r2, v1, v2, v3);
|
|
DivRem(r4, ref r3, ref r2, ref r1, v1, v2, v3);
|
|
DivRem(r3, ref r2, ref r1, ref r0, v1, v2, v3);
|
|
Create(out c, r0, r1, r2, 0);
|
|
RightShift64(ref c, d);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a % (BigInteger)b);
|
|
}
|
|
|
|
private static void Remainder256(out UInt128 c, ref UInt256 a, ref UInt128 b)
|
|
{
|
|
var d = 32 - GetBitLength(b.r3);
|
|
UInt128 v;
|
|
LeftShift64(out v, ref b, d);
|
|
var v1 = v.r3;
|
|
var v2 = v.r2;
|
|
var v3 = v.r1;
|
|
var v4 = v.r0;
|
|
UInt256 rem;
|
|
var r8 = (uint)LeftShift64(out rem, ref a, d);
|
|
var r7 = rem.r7;
|
|
var r6 = rem.r6;
|
|
var r5 = rem.r5;
|
|
var r4 = rem.r4;
|
|
var r3 = rem.r3;
|
|
var r2 = rem.r2;
|
|
var r1 = rem.r1;
|
|
var r0 = rem.r0;
|
|
DivRem(r8, ref r7, ref r6, ref r5, ref r4, v1, v2, v3, v4);
|
|
DivRem(r7, ref r6, ref r5, ref r4, ref r3, v1, v2, v3, v4);
|
|
DivRem(r6, ref r5, ref r4, ref r3, ref r2, v1, v2, v3, v4);
|
|
DivRem(r5, ref r4, ref r3, ref r2, ref r1, v1, v2, v3, v4);
|
|
DivRem(r4, ref r3, ref r2, ref r1, ref r0, v1, v2, v3, v4);
|
|
Create(out c, r0, r1, r2, r3);
|
|
RightShift64(ref c, d);
|
|
Debug.Assert((BigInteger)c == (BigInteger)a % (BigInteger)b);
|
|
}
|
|
|
|
private static ulong Q(uint u0, uint u1, uint u2, uint v1, uint v2)
|
|
{
|
|
var u0u1 = (ulong)u0 << 32 | u1;
|
|
var qhat = u0 == v1 ? uint.MaxValue : u0u1 / v1;
|
|
var r = u0u1 - qhat * v1;
|
|
if (r == (uint)r && v2 * qhat > (r << 32 | u2))
|
|
{
|
|
--qhat;
|
|
r += v1;
|
|
if (r == (uint)r && v2 * qhat > (r << 32 | u2))
|
|
{
|
|
--qhat;
|
|
r += v1;
|
|
}
|
|
}
|
|
return qhat;
|
|
}
|
|
|
|
private static uint DivRem(uint u0, ref uint u1, ref uint u2, uint v1, uint v2)
|
|
{
|
|
var qhat = Q(u0, u1, u2, v1, v2);
|
|
var carry = qhat * v2;
|
|
var borrow = (long)u2 - (uint)carry;
|
|
carry >>= 32;
|
|
u2 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v1;
|
|
borrow += (long)u1 - (uint)carry;
|
|
carry >>= 32;
|
|
u1 = (uint)borrow;
|
|
borrow >>= 32;
|
|
borrow += (long)u0 - (uint)carry;
|
|
if (borrow != 0)
|
|
{
|
|
--qhat;
|
|
carry = (ulong)u2 + v2;
|
|
u2 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u1 + v1;
|
|
u1 = (uint)carry;
|
|
}
|
|
return (uint)qhat;
|
|
}
|
|
|
|
private static uint DivRem(uint u0, ref uint u1, ref uint u2, ref uint u3, uint v1, uint v2, uint v3)
|
|
{
|
|
var qhat = Q(u0, u1, u2, v1, v2);
|
|
var carry = qhat * v3;
|
|
var borrow = (long)u3 - (uint)carry;
|
|
carry >>= 32;
|
|
u3 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v2;
|
|
borrow += (long)u2 - (uint)carry;
|
|
carry >>= 32;
|
|
u2 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v1;
|
|
borrow += (long)u1 - (uint)carry;
|
|
carry >>= 32;
|
|
u1 = (uint)borrow;
|
|
borrow >>= 32;
|
|
borrow += (long)u0 - (uint)carry;
|
|
if (borrow != 0)
|
|
{
|
|
--qhat;
|
|
carry = (ulong)u3 + v3;
|
|
u3 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u2 + v2;
|
|
u2 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u1 + v1;
|
|
u1 = (uint)carry;
|
|
}
|
|
return (uint)qhat;
|
|
}
|
|
|
|
private static uint DivRem(uint u0, ref uint u1, ref uint u2, ref uint u3, ref uint u4, uint v1, uint v2, uint v3, uint v4)
|
|
{
|
|
var qhat = Q(u0, u1, u2, v1, v2);
|
|
var carry = qhat * v4;
|
|
var borrow = (long)u4 - (uint)carry;
|
|
carry >>= 32;
|
|
u4 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v3;
|
|
borrow += (long)u3 - (uint)carry;
|
|
carry >>= 32;
|
|
u3 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v2;
|
|
borrow += (long)u2 - (uint)carry;
|
|
carry >>= 32;
|
|
u2 = (uint)borrow;
|
|
borrow >>= 32;
|
|
carry += qhat * v1;
|
|
borrow += (long)u1 - (uint)carry;
|
|
carry >>= 32;
|
|
u1 = (uint)borrow;
|
|
borrow >>= 32;
|
|
borrow += (long)u0 - (uint)carry;
|
|
if (borrow != 0)
|
|
{
|
|
--qhat;
|
|
carry = (ulong)u4 + v4;
|
|
u4 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u3 + v3;
|
|
u3 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u2 + v2;
|
|
u2 = (uint)carry;
|
|
carry >>= 32;
|
|
carry += (ulong)u1 + v1;
|
|
u1 = (uint)carry;
|
|
}
|
|
return (uint)qhat;
|
|
}
|
|
|
|
public static void ModAdd(out UInt128 c, ref UInt128 a, ref UInt128 b, ref UInt128 modulus)
|
|
{
|
|
Add(out c, ref a, ref b);
|
|
if (!LessThan(ref c, ref modulus) || LessThan(ref c, ref a) && LessThan(ref c, ref b))
|
|
Subtract(ref c, ref modulus);
|
|
}
|
|
|
|
public static void ModSub(out UInt128 c, ref UInt128 a, ref UInt128 b, ref UInt128 modulus)
|
|
{
|
|
Subtract(out c, ref a, ref b);
|
|
if (LessThan(ref a, ref b))
|
|
Add(ref c, ref modulus);
|
|
}
|
|
|
|
public static void ModMul(out UInt128 c, ref UInt128 a, ref UInt128 b, ref UInt128 modulus)
|
|
{
|
|
if (modulus.s1 == 0)
|
|
{
|
|
UInt128 product;
|
|
Multiply64(out product, a.s0, b.s0);
|
|
Create(out c, UInt128.Remainder(ref product, modulus.s0));
|
|
}
|
|
else
|
|
{
|
|
UInt256 product;
|
|
Multiply(out product, ref a, ref b);
|
|
Remainder(out c, ref product, ref modulus);
|
|
}
|
|
}
|
|
|
|
public static void ModMul(ref UInt128 a, ref UInt128 b, ref UInt128 modulus)
|
|
{
|
|
if (modulus.s1 == 0)
|
|
{
|
|
UInt128 product;
|
|
Multiply64(out product, a.s0, b.s0);
|
|
Create(out a, UInt128.Remainder(ref product, modulus.s0));
|
|
}
|
|
else
|
|
{
|
|
UInt256 product;
|
|
Multiply(out product, ref a, ref b);
|
|
Remainder(out a, ref product, ref modulus);
|
|
}
|
|
}
|
|
|
|
public static void ModPow(out UInt128 result, ref UInt128 value, ref UInt128 exponent, ref UInt128 modulus)
|
|
{
|
|
result = one;
|
|
var v = value;
|
|
var e = exponent.s0;
|
|
if (exponent.s1 != 0)
|
|
{
|
|
for (var i = 0; i < 64; i++)
|
|
{
|
|
if ((e & 1) != 0)
|
|
ModMul(ref result, ref v, ref modulus);
|
|
ModMul(ref v, ref v, ref modulus);
|
|
e >>= 1;
|
|
}
|
|
e = exponent.s1;
|
|
}
|
|
while (e != 0)
|
|
{
|
|
if ((e & 1) != 0)
|
|
ModMul(ref result, ref v, ref modulus);
|
|
if (e != 1)
|
|
ModMul(ref v, ref v, ref modulus);
|
|
e >>= 1;
|
|
}
|
|
Debug.Assert(BigInteger.ModPow(value, exponent, modulus) == result);
|
|
}
|
|
|
|
public static void Shift(out UInt128 c, ref UInt128 a, int d)
|
|
{
|
|
if (d < 0)
|
|
RightShift(out c, ref a, -d);
|
|
else
|
|
LeftShift(out c, ref a, d);
|
|
}
|
|
|
|
public static void ArithmeticShift(out UInt128 c, ref UInt128 a, int d)
|
|
{
|
|
if (d < 0)
|
|
ArithmeticRightShift(out c, ref a, -d);
|
|
else
|
|
LeftShift(out c, ref a, d);
|
|
}
|
|
|
|
public static ulong LeftShift64(out UInt128 c, ref UInt128 a, int d)
|
|
{
|
|
if (d == 0)
|
|
{
|
|
c = a;
|
|
return 0;
|
|
}
|
|
var dneg = 64 - d;
|
|
c.s1 = a.s1 << d | a.s0 >> dneg;
|
|
c.s0 = a.s0 << d;
|
|
return a.s1 >> dneg;
|
|
}
|
|
|
|
private static ulong LeftShift64(out UInt256 c, ref UInt256 a, int d)
|
|
{
|
|
if (d == 0)
|
|
{
|
|
c = a;
|
|
return 0;
|
|
}
|
|
var dneg = 64 - d;
|
|
c.s3 = a.s3 << d | a.s2 >> dneg;
|
|
c.s2 = a.s2 << d | a.s1 >> dneg;
|
|
c.s1 = a.s1 << d | a.s0 >> dneg;
|
|
c.s0 = a.s0 << d;
|
|
return a.s3 >> dneg;
|
|
}
|
|
|
|
public static void LeftShift(out UInt128 c, ref UInt128 a, int b)
|
|
{
|
|
if (b < 64)
|
|
LeftShift64(out c, ref a, b);
|
|
else if (b == 64)
|
|
{
|
|
c.s0 = 0;
|
|
c.s1 = a.s0;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
c.s0 = 0;
|
|
c.s1 = a.s0 << (b - 64);
|
|
}
|
|
}
|
|
|
|
public static void RightShift64(out UInt128 c, ref UInt128 a, int b)
|
|
{
|
|
if (b == 0)
|
|
c = a;
|
|
else
|
|
{
|
|
c.s0 = a.s0 >> b | a.s1 << (64 - b);
|
|
c.s1 = a.s1 >> b;
|
|
}
|
|
}
|
|
|
|
public static void RightShift(out UInt128 c, ref UInt128 a, int b)
|
|
{
|
|
if (b < 64)
|
|
RightShift64(out c, ref a, b);
|
|
else if (b == 64)
|
|
{
|
|
c.s0 = a.s1;
|
|
c.s1 = 0;
|
|
}
|
|
else
|
|
{
|
|
c.s0 = a.s1 >> (b - 64);
|
|
c.s1 = 0;
|
|
}
|
|
}
|
|
|
|
public static void ArithmeticRightShift64(out UInt128 c, ref UInt128 a, int b)
|
|
{
|
|
if (b == 0)
|
|
c = a;
|
|
else
|
|
{
|
|
c.s0 = a.s0 >> b | a.s1 << (64 - b);
|
|
c.s1 = (ulong)((long)a.s1 >> b);
|
|
}
|
|
}
|
|
|
|
public static void ArithmeticRightShift(out UInt128 c, ref UInt128 a, int b)
|
|
{
|
|
if (b < 64)
|
|
ArithmeticRightShift64(out c, ref a, b);
|
|
else if (b == 64)
|
|
{
|
|
c.s0 = a.s1;
|
|
c.s1 = (ulong)((long)a.s1 >> 63);
|
|
}
|
|
else
|
|
{
|
|
c.s0 = a.s1 >> (b - 64);
|
|
c.s1 = (ulong)((long)a.s1 >> 63);
|
|
}
|
|
}
|
|
|
|
public static void And(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
c.s0 = a.s0 & b.s0;
|
|
c.s1 = a.s1 & b.s1;
|
|
}
|
|
|
|
public static void Or(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
c.s0 = a.s0 | b.s0;
|
|
c.s1 = a.s1 | b.s1;
|
|
}
|
|
|
|
public static void ExclusiveOr(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
c.s0 = a.s0 ^ b.s0;
|
|
c.s1 = a.s1 ^ b.s1;
|
|
}
|
|
|
|
public static void Not(out UInt128 c, ref UInt128 a)
|
|
{
|
|
c.s0 = ~a.s0;
|
|
c.s1 = ~a.s1;
|
|
}
|
|
|
|
public static void Negate(ref UInt128 a)
|
|
{
|
|
var s0 = a.s0;
|
|
a.s0 = 0 - s0;
|
|
a.s1 = 0 - a.s1;
|
|
if (s0 > 0)
|
|
--a.s1;
|
|
}
|
|
|
|
|
|
public static void Negate(out UInt128 c, ref UInt128 a)
|
|
{
|
|
c.s0 = 0 - a.s0;
|
|
c.s1 = 0 - a.s1;
|
|
if (a.s0 > 0)
|
|
--c.s1;
|
|
Debug.Assert((BigInteger)c == (BigInteger)(~a + 1));
|
|
}
|
|
|
|
public static void Pow(out UInt128 result, ref UInt128 value, uint exponent)
|
|
{
|
|
result = one;
|
|
while (exponent != 0)
|
|
{
|
|
|
|
if ((exponent & 1) != 0)
|
|
{
|
|
var previous = result;
|
|
Multiply(out result, ref previous, ref value);
|
|
}
|
|
if (exponent != 1)
|
|
{
|
|
var previous = value;
|
|
Square(out value, ref previous);
|
|
}
|
|
exponent >>= 1;
|
|
}
|
|
}
|
|
|
|
public static UInt128 Pow(UInt128 value, uint exponent)
|
|
{
|
|
UInt128 result;
|
|
Pow(out result, ref value, exponent);
|
|
return result;
|
|
}
|
|
|
|
private const int maxRepShift = 53;
|
|
private static readonly ulong maxRep = (ulong)1 << maxRepShift;
|
|
private static readonly UInt128 maxRepSquaredHigh = (ulong)1 << (2 * maxRepShift - 64);
|
|
|
|
public static ulong FloorSqrt(UInt128 a)
|
|
{
|
|
if (a.s1 == 0 && a.s0 <= maxRep)
|
|
return (ulong)Math.Sqrt(a.s0);
|
|
var s = (ulong)Math.Sqrt(ConvertToDouble(ref a));
|
|
if (a.s1 < maxRepSquaredHigh)
|
|
{
|
|
UInt128 s2;
|
|
Square(out s2, s);
|
|
var r = a.s0 - s2.s0;
|
|
if (r > long.MaxValue)
|
|
--s;
|
|
else if (r - (s << 1) <= long.MaxValue)
|
|
++s;
|
|
Debug.Assert((BigInteger)s * s <= a && (BigInteger)(s + 1) * (s + 1) > a);
|
|
return s;
|
|
}
|
|
s = FloorSqrt(ref a, s);
|
|
Debug.Assert((BigInteger)s * s <= a && (BigInteger)(s + 1) * (s + 1) > a);
|
|
return s;
|
|
}
|
|
|
|
public static ulong CeilingSqrt(UInt128 a)
|
|
{
|
|
if (a.s1 == 0 && a.s0 <= maxRep)
|
|
return (ulong)Math.Ceiling(Math.Sqrt(a.s0));
|
|
var s = (ulong)Math.Ceiling(Math.Sqrt(ConvertToDouble(ref a)));
|
|
if (a.s1 < maxRepSquaredHigh)
|
|
{
|
|
UInt128 s2;
|
|
Square(out s2, s);
|
|
var r = s2.s0 - a.s0;
|
|
if (r > long.MaxValue)
|
|
++s;
|
|
else if (r - (s << 1) <= long.MaxValue)
|
|
--s;
|
|
Debug.Assert((BigInteger)(s - 1) * (s - 1) < a && (BigInteger)s * s >= a);
|
|
return s;
|
|
}
|
|
s = FloorSqrt(ref a, s);
|
|
UInt128 square;
|
|
Square(out square, s);
|
|
if (square.S0 != a.S0 || square.S1 != a.S1)
|
|
++s;
|
|
Debug.Assert((BigInteger)(s - 1) * (s - 1) < a && (BigInteger)s * s >= a);
|
|
return s;
|
|
}
|
|
|
|
private static ulong FloorSqrt(ref UInt128 a, ulong s)
|
|
{
|
|
var sprev = (ulong)0;
|
|
UInt128 div;
|
|
UInt128 sum;
|
|
while (true)
|
|
{
|
|
// Equivalent to:
|
|
// snext = (a / s + s) / 2;
|
|
Divide(out div, ref a, s);
|
|
Add(out sum, ref div, s);
|
|
var snext = sum.S0 >> 1;
|
|
if (sum.S1 != 0)
|
|
snext |= (ulong)1 << 63;
|
|
if (snext == sprev)
|
|
{
|
|
if (snext < s)
|
|
s = snext;
|
|
break;
|
|
}
|
|
sprev = s;
|
|
s = snext;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public static ulong FloorCbrt(UInt128 a)
|
|
{
|
|
var s = (ulong)Math.Pow(ConvertToDouble(ref a), (double)1 / 3);
|
|
UInt128 s3;
|
|
Cube(out s3, s);
|
|
if (a < s3)
|
|
--s;
|
|
else
|
|
{
|
|
UInt128 sum;
|
|
Multiply(out sum, 3 * s, s + 1);
|
|
UInt128 diff;
|
|
Subtract(out diff, ref a, ref s3);
|
|
if (LessThan(ref sum, ref diff))
|
|
++s;
|
|
}
|
|
Debug.Assert((BigInteger)s * s * s <= a && (BigInteger)(s + 1) * (s + 1) * (s + 1) > a);
|
|
return s;
|
|
}
|
|
|
|
public static ulong CeilingCbrt(UInt128 a)
|
|
{
|
|
var s = (ulong)Math.Ceiling(Math.Pow(ConvertToDouble(ref a), (double)1 / 3));
|
|
UInt128 s3;
|
|
Cube(out s3, s);
|
|
if (s3 < a)
|
|
++s;
|
|
else
|
|
{
|
|
UInt128 sum;
|
|
Multiply(out sum, 3 * s, s + 1);
|
|
UInt128 diff;
|
|
Subtract(out diff, ref s3, ref a);
|
|
if (LessThan(ref sum, ref diff))
|
|
--s;
|
|
}
|
|
Debug.Assert((BigInteger)(s - 1) * (s - 1) * (s - 1) < a && (BigInteger)s * s * s >= a);
|
|
return s;
|
|
}
|
|
|
|
public static UInt128 Min(UInt128 a, UInt128 b)
|
|
{
|
|
if (LessThan(ref a, ref b))
|
|
return a;
|
|
return b;
|
|
}
|
|
|
|
public static UInt128 Max(UInt128 a, UInt128 b)
|
|
{
|
|
if (LessThan(ref b, ref a))
|
|
return a;
|
|
return b;
|
|
}
|
|
|
|
public static double Log(UInt128 a)
|
|
{
|
|
return Log(a, Math.E);
|
|
}
|
|
|
|
public static double Log10(UInt128 a)
|
|
{
|
|
return Log(a, 10);
|
|
}
|
|
|
|
public static double Log(UInt128 a, double b)
|
|
{
|
|
return Math.Log(ConvertToDouble(ref a), b);
|
|
}
|
|
|
|
public static UInt128 Add(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Add(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Subtract(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Subtract(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Multiply(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Multiply(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Divide(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Divide(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 Remainder(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
Remainder(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 DivRem(UInt128 a, UInt128 b, out UInt128 remainder)
|
|
{
|
|
UInt128 c;
|
|
Divide(out c, ref a, ref b);
|
|
Remainder(out remainder, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 ModAdd(UInt128 a, UInt128 b, UInt128 modulus)
|
|
{
|
|
UInt128 c;
|
|
ModAdd(out c, ref a, ref b, ref modulus);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 ModSub(UInt128 a, UInt128 b, UInt128 modulus)
|
|
{
|
|
UInt128 c;
|
|
ModSub(out c, ref a, ref b, ref modulus);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 ModMul(UInt128 a, UInt128 b, UInt128 modulus)
|
|
{
|
|
UInt128 c;
|
|
ModMul(out c, ref a, ref b, ref modulus);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 ModPow(UInt128 value, UInt128 exponent, UInt128 modulus)
|
|
{
|
|
UInt128 result;
|
|
ModPow(out result, ref value, ref exponent, ref modulus);
|
|
return result;
|
|
}
|
|
|
|
public static UInt128 Negate(UInt128 a)
|
|
{
|
|
UInt128 c;
|
|
Negate(out c, ref a);
|
|
return c;
|
|
}
|
|
|
|
public static UInt128 GreatestCommonDivisor(UInt128 a, UInt128 b)
|
|
{
|
|
UInt128 c;
|
|
GreatestCommonDivisor(out c, ref a, ref b);
|
|
return c;
|
|
}
|
|
|
|
private static void RightShift64(ref UInt128 c, int d)
|
|
{
|
|
if (d == 0)
|
|
return;
|
|
c.s0 = c.s1 << (64 - d) | c.s0 >> d;
|
|
c.s1 >>= d;
|
|
}
|
|
|
|
public static void RightShift(ref UInt128 c, int d)
|
|
{
|
|
if (d < 64)
|
|
RightShift64(ref c, d);
|
|
else
|
|
{
|
|
c.s0 = c.s1 >> (d - 64);
|
|
c.s1 = 0;
|
|
}
|
|
}
|
|
|
|
public static void Shift(ref UInt128 c, int d)
|
|
{
|
|
if (d < 0)
|
|
RightShift(ref c, -d);
|
|
else
|
|
LeftShift(ref c, d);
|
|
}
|
|
|
|
public static void ArithmeticShift(ref UInt128 c, int d)
|
|
{
|
|
if (d < 0)
|
|
ArithmeticRightShift(ref c, -d);
|
|
else
|
|
LeftShift(ref c, d);
|
|
}
|
|
|
|
public static void RightShift(ref UInt128 c)
|
|
{
|
|
c.s0 = c.s1 << 63 | c.s0 >> 1;
|
|
c.s1 >>= 1;
|
|
}
|
|
|
|
private static void ArithmeticRightShift64(ref UInt128 c, int d)
|
|
{
|
|
if (d == 0)
|
|
return;
|
|
c.s0 = c.s1 << (64 - d) | c.s0 >> d;
|
|
c.s1 = (ulong)((long)c.s1 >> d);
|
|
}
|
|
|
|
public static void ArithmeticRightShift(ref UInt128 c, int d)
|
|
{
|
|
if (d < 64)
|
|
ArithmeticRightShift64(ref c, d);
|
|
else
|
|
{
|
|
c.s0 = (ulong)((long)c.s1 >> (d - 64));
|
|
c.s1 = 0;
|
|
}
|
|
}
|
|
|
|
public static void ArithmeticRightShift(ref UInt128 c)
|
|
{
|
|
c.s0 = c.s1 << 63 | c.s0 >> 1;
|
|
c.s1 = (ulong)((long)c.s1 >> 1);
|
|
}
|
|
|
|
private static ulong LeftShift64(ref UInt128 c, int d)
|
|
{
|
|
if (d == 0)
|
|
return 0;
|
|
var dneg = 64 - d;
|
|
var result = c.s1 >> dneg;
|
|
c.s1 = c.s1 << d | c.s0 >> dneg;
|
|
c.s0 <<= d;
|
|
return result;
|
|
}
|
|
|
|
public static void LeftShift(ref UInt128 c, int d)
|
|
{
|
|
if (d < 64)
|
|
LeftShift64(ref c, d);
|
|
else
|
|
{
|
|
c.s1 = c.s0 << (d - 64);
|
|
c.s0 = 0;
|
|
}
|
|
}
|
|
|
|
public static void LeftShift(ref UInt128 c)
|
|
{
|
|
c.s1 = c.s1 << 1 | c.s0 >> 63;
|
|
c.s0 <<= 1;
|
|
}
|
|
|
|
public static void Swap(ref UInt128 a, ref UInt128 b)
|
|
{
|
|
var as0 = a.s0;
|
|
var as1 = a.s1;
|
|
a.s0 = b.s0;
|
|
a.s1 = b.s1;
|
|
b.s0 = as0;
|
|
b.s1 = as1;
|
|
}
|
|
|
|
public static void GreatestCommonDivisor(out UInt128 c, ref UInt128 a, ref UInt128 b)
|
|
{
|
|
// Check whether one number is > 64 bits and the other is <= 64 bits and both are non-zero.
|
|
UInt128 a1, b1;
|
|
if ((a.s1 == 0) != (b.s1 == 0) && !a.IsZero && !b.IsZero)
|
|
{
|
|
// Perform a normal step so that both a and b are <= 64 bits.
|
|
if (LessThan(ref a, ref b))
|
|
{
|
|
a1 = a;
|
|
Remainder(out b1, ref b, ref a);
|
|
}
|
|
else
|
|
{
|
|
b1 = b;
|
|
Remainder(out a1, ref a, ref b);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
a1 = a;
|
|
b1 = b;
|
|
}
|
|
|
|
// Make sure neither is zero.
|
|
if (a1.IsZero)
|
|
{
|
|
c = b1;
|
|
return;
|
|
}
|
|
if (b1.IsZero)
|
|
{
|
|
c = a1;
|
|
return;
|
|
}
|
|
|
|
// Ensure a >= b.
|
|
if (LessThan(ref a1, ref b1))
|
|
Swap(ref a1, ref b1);
|
|
|
|
// Lehmer-Euclid algorithm.
|
|
// See: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.693
|
|
while (a1.s1 != 0 && !b.IsZero)
|
|
{
|
|
// Extract the high 63 bits of a and b.
|
|
var norm = 63 - GetBitLength(a1.s1);
|
|
UInt128 ahat, bhat;
|
|
Shift(out ahat, ref a1, norm);
|
|
Shift(out bhat, ref b1, norm);
|
|
var uhat = (long)ahat.s1;
|
|
var vhat = (long)bhat.s1;
|
|
|
|
// Check whether q exceeds single-precision.
|
|
if (vhat == 0)
|
|
{
|
|
// Perform a normal step and try again.
|
|
UInt128 rem;
|
|
Remainder(out rem, ref a1, ref b1);
|
|
a1 = b1;
|
|
b1 = rem;
|
|
continue;
|
|
}
|
|
|
|
// Perform steps using signed single-precision arithmetic.
|
|
var x0 = (long)1;
|
|
var y0 = (long)0;
|
|
var x1 = (long)0;
|
|
var y1 = (long)1;
|
|
var even = true;
|
|
while (true)
|
|
{
|
|
// Calculate quotient, cosquence pair, and update uhat and vhat.
|
|
var q = uhat / vhat;
|
|
var x2 = x0 - q * x1;
|
|
var y2 = y0 - q * y1;
|
|
var t = uhat;
|
|
uhat = vhat;
|
|
vhat = t - q * vhat;
|
|
even = !even;
|
|
|
|
// Apply Jebelean's termination condition
|
|
// to check whether q is valid.
|
|
if (even)
|
|
{
|
|
if (vhat < -x2 || uhat - vhat < y2 - y1)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (vhat < -y2 || uhat - vhat < x2 - x1)
|
|
break;
|
|
}
|
|
|
|
// Adjust cosequence history.
|
|
x0 = x1; y0 = y1; x1 = x2; y1 = y2;
|
|
}
|
|
|
|
// Check whether a normal step is necessary.
|
|
if (x0 == 1 && y0 == 0)
|
|
{
|
|
UInt128 rem;
|
|
Remainder(out rem, ref a1, ref b1);
|
|
a1 = b1;
|
|
b1 = rem;
|
|
continue;
|
|
}
|
|
|
|
// Back calculate a and b from the last valid cosequence pairs.
|
|
UInt128 anew, bnew;
|
|
if (even)
|
|
{
|
|
AddProducts(out anew, y0, ref b1, x0, ref a1);
|
|
AddProducts(out bnew, x1, ref a1, y1, ref b1);
|
|
}
|
|
else
|
|
{
|
|
AddProducts(out anew, x0, ref a1, y0, ref b1);
|
|
AddProducts(out bnew, y1, ref b1, x1, ref a1);
|
|
}
|
|
a1 = anew;
|
|
b1 = bnew;
|
|
}
|
|
|
|
// Check whether we have any 64 bit work left.
|
|
if (!b1.IsZero)
|
|
{
|
|
var a2 = a1.s0;
|
|
var b2 = b1.s0;
|
|
|
|
// Perform 64 bit steps.
|
|
while (a2 > uint.MaxValue && b2 != 0)
|
|
{
|
|
var t = a2 % b2;
|
|
a2 = b2;
|
|
b2 = t;
|
|
}
|
|
|
|
// Check whether we have any 32 bit work left.
|
|
if (b2 != 0)
|
|
{
|
|
var a3 = (uint)a2;
|
|
var b3 = (uint)b2;
|
|
|
|
// Perform 32 bit steps.
|
|
while (b3 != 0)
|
|
{
|
|
var t = a3 % b3;
|
|
a3 = b3;
|
|
b3 = t;
|
|
}
|
|
|
|
Create(out c, a3);
|
|
}
|
|
else
|
|
Create(out c, a2);
|
|
}
|
|
else
|
|
c = a1;
|
|
}
|
|
|
|
private static void AddProducts(out UInt128 result, long x, ref UInt128 u, long y, ref UInt128 v)
|
|
{
|
|
// Compute x * u + y * v assuming y is negative and the result is positive and fits in 128 bits.
|
|
UInt128 product1;
|
|
Multiply(out product1, ref u, (ulong)x);
|
|
UInt128 product2;
|
|
Multiply(out product2, ref v, (ulong)(-y));
|
|
Subtract(out result, ref product1, ref product2);
|
|
}
|
|
|
|
public static int Compare(UInt128 a, UInt128 b)
|
|
{
|
|
return a.CompareTo(b);
|
|
}
|
|
|
|
private static byte[] bitLength = Enumerable.Range(0, byte.MaxValue + 1)
|
|
.Select(value =>
|
|
{
|
|
int count;
|
|
for (count = 0; value != 0; count++)
|
|
value >>= 1;
|
|
return (byte)count;
|
|
}).ToArray();
|
|
|
|
private static int GetBitLength(uint value)
|
|
{
|
|
var tt = value >> 16;
|
|
if (tt != 0)
|
|
{
|
|
var t = tt >> 8;
|
|
if (t != 0)
|
|
return bitLength[t] + 24;
|
|
return bitLength[tt] + 16;
|
|
}
|
|
else
|
|
{
|
|
var t = value >> 8;
|
|
if (t != 0)
|
|
return bitLength[t] + 8;
|
|
return bitLength[value];
|
|
}
|
|
}
|
|
|
|
private static int GetBitLength(ulong value)
|
|
{
|
|
var r1 = value >> 32;
|
|
if (r1 != 0)
|
|
return GetBitLength((uint)r1) + 32;
|
|
return GetBitLength((uint)value);
|
|
}
|
|
|
|
public static void Reduce(out UInt128 w, ref UInt128 u, ref UInt128 v, ref UInt128 n, ulong k0)
|
|
{
|
|
UInt128 carry;
|
|
Multiply64(out carry, u.s0, v.s0);
|
|
var t0 = carry.s0;
|
|
Multiply64(out carry, u.s1, v.s0, carry.s1);
|
|
var t1 = carry.s0;
|
|
var t2 = carry.s1;
|
|
|
|
var m = t0 * k0;
|
|
Multiply64(out carry, m, n.s1, MultiplyHigh64(m, n.s0, t0));
|
|
Add(ref carry, t1);
|
|
t0 = carry.s0;
|
|
Add(out carry, carry.s1, t2);
|
|
t1 = carry.s0;
|
|
t2 = carry.s1;
|
|
|
|
Multiply64(out carry, u.s0, v.s1, t0);
|
|
t0 = carry.s0;
|
|
Multiply64(out carry, u.s1, v.s1, carry.s1);
|
|
Add(ref carry, t1);
|
|
t1 = carry.s0;
|
|
Add(out carry, carry.s1, t2);
|
|
t2 = carry.s0;
|
|
var t3 = carry.s1;
|
|
|
|
m = t0 * k0;
|
|
Multiply64(out carry, m, n.s1, MultiplyHigh64(m, n.s0, t0));
|
|
Add(ref carry, t1);
|
|
t0 = carry.s0;
|
|
Add(out carry, carry.s1, t2);
|
|
t1 = carry.s0;
|
|
t2 = t3 + carry.s1;
|
|
|
|
Create(out w, t0, t1);
|
|
if (t2 != 0 || !LessThan(ref w, ref n))
|
|
Subtract(ref w, ref n);
|
|
}
|
|
|
|
public static void Reduce(out UInt128 w, ref UInt128 t, ref UInt128 n, ulong k0)
|
|
{
|
|
UInt128 carry;
|
|
var t0 = t.s0;
|
|
var t1 = t.s1;
|
|
var t2 = (ulong)0;
|
|
|
|
for (var i = 0; i < 2; i++)
|
|
{
|
|
var m = t0 * k0;
|
|
Multiply64(out carry, m, n.s1, MultiplyHigh64(m, n.s0, t0));
|
|
Add(ref carry, t1);
|
|
t0 = carry.s0;
|
|
Add(out carry, carry.s1, t2);
|
|
t1 = carry.s0;
|
|
t2 = carry.s1;
|
|
}
|
|
|
|
Create(out w, t0, t1);
|
|
if (t2 != 0 || !LessThan(ref w, ref n))
|
|
Subtract(ref w, ref n);
|
|
}
|
|
|
|
public static UInt128 Reduce(UInt128 u, UInt128 v, UInt128 n, ulong k0)
|
|
{
|
|
UInt128 w;
|
|
Reduce(out w, ref u, ref v, ref n, k0);
|
|
return w;
|
|
}
|
|
|
|
public static UInt128 Reduce(UInt128 t, UInt128 n, ulong k0)
|
|
{
|
|
UInt128 w;
|
|
Reduce(out w, ref t, ref n, k0);
|
|
return w;
|
|
}
|
|
}
|
|
}
|