Skip to content

Instantly share code, notes, and snippets.

@chengluyu
Created September 14, 2013 08:12
Show Gist options
  • Save chengluyu/6559869 to your computer and use it in GitHub Desktop.
Save chengluyu/6559869 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
namespace Microsoft.MicrosoftMath
{
internal struct UInteger : IComparable<UInteger>, IEquatable<UInteger>
{
private readonly uint[] data;
private static UInteger[] Base10Powers;
private static readonly uint[] BitMaskArray;
private static readonly int[] power2;
private static readonly char[] digitChars;
internal bool IsZero
{
get
{
return this.data == null;
}
}
internal bool IsOne
{
get
{
return this.data != null && this.data.Length == 1 && this.data[0] == 1u;
}
}
internal bool IsOdd
{
get
{
return this.data != null && (this.data[0] & 1u) != 0u;
}
}
internal int DwordCount
{
get
{
if (this.data == null)
{
return 0;
}
return this.data.Length;
}
}
internal uint LowestDword
{
get
{
if (this.data == null)
{
return 0u;
}
return this.data[0];
}
}
internal int BitCount
{
get
{
if (this.data != null)
{
uint num = this.data[this.data.Length - 1];
int num2 = (this.data.Length - 1) * 32;
if ((num & 4294901760u) != 0u)
{
num2 += 16;
num &= 4294901760u;
}
if ((num & 4278255360u) != 0u)
{
num2 += 8;
num &= 4278255360u;
}
if ((num & 4042322160u) != 0u)
{
num2 += 4;
num &= 4042322160u;
}
if ((num & 3435973836u) != 0u)
{
num2 += 2;
num &= 3435973836u;
}
if ((num & 2863311530u) != 0u)
{
num2++;
num &= 2863311530u;
}
return num2 + 1;
}
return 0;
}
}
private static void CheckBase10Powers(int length)
{
if (length > 2467)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
if (length > 0 && UInteger.Base10Powers.Length < length)
{
object syncRoot;
Monitor.Enter(syncRoot = UInteger.Base10Powers.SyncRoot);
try
{
if (UInteger.Base10Powers.Length < length)
{
UInteger[] array = new UInteger[length];
for (int i = 0; i < UInteger.Base10Powers.Length; i++)
{
array[i] = UInteger.Base10Powers[i];
}
for (int j = UInteger.Base10Powers.Length; j < length; j++)
{
array[j] = ((j == 0) ? new UInteger(1u) : (array[j - 1] * 10u));
}
UInteger.Base10Powers = array;
}
}
finally
{
Monitor.Exit(syncRoot);
}
}
}
static UInteger()
{
UInteger.Base10Powers = new UInteger[0];
UInteger.BitMaskArray = new uint[]
{
1u,
2u,
4u,
8u,
16u,
32u,
64u,
128u,
256u,
512u,
1024u,
2048u,
4096u,
8192u,
16384u,
32768u,
65536u,
131072u,
262144u,
524288u,
1048576u,
2097152u,
4194304u,
8388608u,
16777216u,
33554432u,
67108864u,
134217728u,
268435456u,
536870912u,
1073741824u,
2147483648u
};
UInteger.power2 = new int[]
{
1,
2,
4,
8,
16
};
UInteger.digitChars = new char[]
{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
};
UInteger.CheckBase10Powers(32);
}
internal UInteger(uint v)
{
this.data = ((v == 0u) ? null : new uint[]
{
v
});
}
internal UInteger(ulong v)
{
if (v == 0uL)
{
this.data = null;
return;
}
if ((v & 18446744069414584320uL) == 0uL)
{
this.data = new uint[]
{
(uint)v
};
return;
}
this.data = new uint[]
{
(uint)v,
(uint)(v >> 32)
};
}
internal UInteger(uint[] dataIn)
{
if (dataIn != null && dataIn.Length > 256)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
int num = -1;
if (dataIn != null)
{
for (int i = dataIn.Length - 1; i >= 0; i--)
{
if (dataIn[i] != 0u)
{
num = i;
break;
}
}
}
if (num < 0)
{
this.data = null;
return;
}
if (num == dataIn.Length - 1)
{
this.data = dataIn;
return;
}
try
{
this.data = new uint[num + 1];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int j = 0; j <= num; j++)
{
this.data[j] = dataIn[j];
}
}
private UInteger(uint[] dataIn, uint highestDword)
{
if (highestDword == 0u || dataIn == null)
{
throw new InternalEvaluationException();
}
if (dataIn.Length > 256)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
try
{
this.data = new uint[dataIn.Length + 1];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int i = 0; i < dataIn.Length; i++)
{
this.data[i] = dataIn[i];
}
this.data[this.data.Length - 1] = highestDword;
}
internal UInteger(string text, uint numberBase)
{
if (text == null || text.Length == 0 || numberBase <= 1u || numberBase > 36u)
{
throw new InternalEvaluationException();
}
int num = -1;
int num2 = 0;
while (num2 < text.Length && text[num2] == '0')
{
num = num2;
num2++;
}
if (num >= 0)
{
text = text.Substring(num + 1);
}
if (text.Length == 0)
{
this = Constants.ZeroUInt;
return;
}
char[] array = text.ToUpper(CultureInfo.InvariantCulture).ToCharArray();
if (numberBase <= 10u)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] < '0' || array[i] > UInteger.digitChars[(int)((UIntPtr)(numberBase - 1u))])
{
throw new ExpressionSyntaxException(SyntaxErrorCode.InvalidNumberDigit);
}
}
}
else
{
for (int j = 0; j < array.Length; j++)
{
if ((array[j] < '0' || array[j] > '9') && (array[j] < 'A' || array[j] > UInteger.digitChars[(int)((UIntPtr)(numberBase - 1u))]))
{
throw new ExpressionSyntaxException(SyntaxErrorCode.InvalidNumberDigit);
}
}
}
if (numberBase == 10u)
{
UInteger.CheckBase10Powers(array.Length);
UInteger uInteger = Constants.ZeroUInt;
for (int k = 0; k < array.Length; k++)
{
uInteger += UInteger.Base10Powers[k] * (uint)(array[array.Length - k - 1] - '0');
}
this = uInteger;
return;
}
if (numberBase == 2u || numberBase == 4u || numberBase == 8u || numberBase == 16u || numberBase == 32u)
{
int s;
switch (numberBase)
{
case 2u:
s = 1;
goto IL_190;
case 3u:
break;
case 4u:
s = 2;
goto IL_190;
default:
if (numberBase == 8u)
{
s = 3;
goto IL_190;
}
if (numberBase == 16u)
{
s = 4;
goto IL_190;
}
break;
}
s = 5;
IL_190:
UInteger uInteger2 = Constants.ZeroUInt;
for (int l = 0; l < array.Length; l++)
{
uInteger2 <<= s;
uInteger2 += UInteger.GetDigitFromChar(array[l]);
}
this = uInteger2;
return;
}
UInteger uInteger3 = new UInteger(UInteger.GetDigitFromChar(array[array.Length - 1]));
UInteger n = new UInteger(numberBase);
for (int m = array.Length - 2; m >= 0; m--)
{
uInteger3 += n * UInteger.GetDigitFromChar(array[m]);
if (m != 0)
{
n *= numberBase;
}
}
this = uInteger3;
}
internal bool GetBit(int n)
{
if (this.data != null)
{
int num = n >> 5;
if (num < this.data.Length)
{
return (this.data[num] & UInteger.BitMaskArray[n & 31]) != 0u;
}
}
return false;
}
internal bool AsUInt64(out ulong v)
{
if (this.data == null)
{
v = 0uL;
return true;
}
if (this.data.Length == 1)
{
v = (ulong)this.data[0];
return true;
}
if (this.data.Length == 2)
{
v = ((ulong)this.data[1] << 32) + (ulong)this.data[0];
return true;
}
v = 0uL;
return false;
}
internal bool IsDecimalDenominator(uint numberBase, out UInteger multiplier, out uint scale)
{
if (numberBase == 10u)
{
return this.IsDecimalDenominatorBase10(out multiplier, out scale);
}
if (numberBase == 2u || numberBase == 4u || numberBase == 8u || numberBase == 16u || numberBase == 32u)
{
int num = -1;
for (int i = 0; i < this.BitCount; i++)
{
if (this.GetBit(i))
{
if (num >= 0)
{
goto IL_B5;
}
num = i;
}
}
if (num >= 0)
{
int num2;
switch (numberBase)
{
case 2u:
num2 = 1;
goto IL_80;
case 3u:
break;
case 4u:
num2 = 2;
goto IL_80;
default:
if (numberBase == 8u)
{
num2 = 3;
goto IL_80;
}
if (numberBase == 16u)
{
num2 = 4;
goto IL_80;
}
break;
}
num2 = 5;
IL_80:
if (num % num2 == 0)
{
multiplier = Constants.OneUInt;
scale = (uint)(num / num2);
}
else
{
multiplier = Constants.OneUInt << num2 - num % num2;
scale = (uint)(num / num2 + 1);
}
return true;
}
}
IL_B5:
multiplier = Constants.ZeroUInt;
scale = 0u;
return false;
}
private bool IsDecimalDenominatorBase10(out UInteger multiplier, out uint scale)
{
if (this.IsZero)
{
multiplier = Constants.ZeroUInt;
scale = 0u;
return false;
}
int num = 0;
int num2 = 0;
int bitCount = this.BitCount;
while (num < bitCount && !this.GetBit(num))
{
num++;
}
UInteger dividend = this >> num;
while (!dividend.IsOne)
{
uint num3;
UInteger uInteger = UInteger.TinyDivMod(dividend, 5u, out num3);
if (num3 != 0u)
{
break;
}
num2++;
dividend = uInteger;
}
if (dividend.IsOne)
{
if (num == num2)
{
multiplier = Constants.OneUInt;
scale = (uint)num;
}
else
{
if (num > num2)
{
multiplier = UInteger.Pow(new UInteger(5u), (uint)(num - num2));
scale = (uint)num;
}
else
{
multiplier = Constants.OneUInt << num2 - num;
scale = (uint)num2;
}
}
return true;
}
multiplier = Constants.ZeroUInt;
scale = 0u;
return false;
}
internal static UInteger Permutation(UInteger n, UInteger k)
{
if (k > n)
{
return Constants.ZeroUInt;
}
if (k == n)
{
return n.Factorial();
}
if (k.IsZero)
{
return Constants.OneUInt;
}
if (n.DwordCount == 1 && n.LowestDword <= 533u)
{
UInteger uInteger = Constants.OneUInt;
for (uint num = n.LowestDword - k.LowestDword + 1u; num <= n.LowestDword; num += 1u)
{
uInteger *= num;
}
return uInteger;
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal static UInteger Permutation(uint n, uint k)
{
return UInteger.Permutation(new UInteger(n), new UInteger(k));
}
internal static UInteger Combination(UInteger n, UInteger k)
{
if (k > n)
{
return Constants.ZeroUInt;
}
if (k == n)
{
return Constants.OneUInt;
}
if (k.IsZero)
{
return Constants.OneUInt;
}
if (n.DwordCount == 1 && n.LowestDword <= 533u)
{
UInteger uInteger = n - k;
if (uInteger > k)
{
UInteger uInteger2 = k;
k = uInteger;
uInteger = uInteger2;
}
UInteger n2 = Constants.OneUInt;
for (uint num = k.LowestDword + 1u; num <= n.LowestDword; num += 1u)
{
n2 *= num;
}
return n2 / uInteger.Factorial();
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal static UInteger Combination(uint n, uint k)
{
return UInteger.Combination(new UInteger(n), new UInteger(k));
}
internal UInteger Factorial()
{
if (this.IsZero)
{
return Constants.OneUInt;
}
if (this.data.Length == 1 && this.LowestDword <= 533u)
{
UInteger uInteger = Constants.OneUInt;
for (uint num = 2u; num <= this.LowestDword; num += 1u)
{
uInteger *= num;
}
return uInteger;
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal static UInteger FactorialMod(UInteger n, UInteger mod)
{
if (n.IsZero)
{
return Constants.OneUInt;
}
if (mod.IsZero)
{
throw new InternalEvaluationException();
}
if (mod <= n)
{
return Constants.ZeroUInt;
}
if (n <= 1000000u)
{
UInteger uInteger = Constants.OneUInt;
for (uint num = 2u; num <= n.LowestDword; num += 1u)
{
uInteger = uInteger * num % mod;
}
return uInteger;
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal UInteger Factorial2()
{
if (this.IsZero)
{
return Constants.OneUInt;
}
if (this.data.Length == 1 && this.LowestDword <= 533u)
{
UInteger uInteger = Constants.OneUInt;
uint num = this.LowestDword;
while (num != 0u && num != 1u)
{
uInteger *= num;
num -= 2u;
}
return uInteger;
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal static UInteger Factorial2Mod(UInteger n, UInteger mod)
{
if (n.IsZero)
{
return Constants.OneUInt;
}
if (mod.IsZero)
{
throw new InternalEvaluationException();
}
if (mod <= n && mod.IsOdd == n.IsOdd)
{
return Constants.ZeroUInt;
}
if (n <= 1000000u)
{
UInteger uInteger = Constants.OneUInt;
uint num = n.LowestDword;
while (num != 0u && num != 1u)
{
uInteger = uInteger * num % mod;
num -= 2u;
}
return uInteger;
}
throw new EvaluationException(EvaluationErrorCode.FactorialCannotPerformOnLargeNumber);
}
internal double GetDoubleValue()
{
double num = 0.0;
if (this.data != null)
{
num = this.data[0];
for (int i = 1; i < this.data.Length; i++)
{
num += this.data[i] * Math.Pow(2.0, (double)(32 * i));
}
}
return num;
}
internal void ToString(StringBuilder buffer, FormatType fmtType, uint numberBase)
{
if (numberBase == 10u)
{
buffer.Append(this.ToStringInternal(numberBase));
return;
}
if (fmtType == FormatType.MathRichEdit)
{
buffer.Append("\\sub{");
buffer.Append(this.ToStringInternal(numberBase));
buffer.Append("\\,");
buffer.Append(numberBase.ToString(CultureInfo.InvariantCulture));
buffer.Append('}');
return;
}
buffer.Append("base(");
buffer.Append(numberBase.ToString(CultureInfo.InvariantCulture));
buffer.Append(", ");
buffer.Append(this.ToStringInternal(numberBase));
buffer.Append(')');
}
public override string ToString()
{
return new string(this.ToStringInternal(10u));
}
internal string ToString(uint numberBase)
{
return new string(this.ToStringInternal(numberBase));
}
internal void ToMathML(XmlWriter writer, uint numberBase)
{
if (numberBase != 10u)
{
writer.WriteStartElement("msub");
}
writer.WriteStartElement("mn");
char[] array = this.ToStringInternal(numberBase);
writer.WriteChars(array, 0, array.Length);
writer.WriteEndElement();
if (numberBase != 10u)
{
writer.WriteStartElement("mn");
writer.WriteString(numberBase.ToString(CultureInfo.InvariantCulture));
writer.WriteEndElement();
writer.WriteEndElement();
}
}
private char[] ToStringInternal(uint numberBase)
{
if (this.IsZero)
{
return new char[]
{
'0'
};
}
if (numberBase <= 1u)
{
throw new InternalEvaluationException();
}
if (numberBase == 10u)
{
return this.ToStringBase10();
}
if (numberBase == 2u || numberBase == 4u || numberBase == 8u || numberBase == 16u || numberBase == 32u)
{
return this.ToStringBinary(numberBase);
}
if (numberBase <= 36u)
{
return this.ToStringGeneralBase(numberBase);
}
return this.ToStringLargeBase(numberBase);
}
private char[] ToStringBinary(uint numberBase)
{
int num;
if (numberBase <= 8u)
{
switch (numberBase)
{
case 2u:
num = 1;
goto IL_4C;
case 3u:
break;
case 4u:
num = 2;
goto IL_4C;
default:
if (numberBase == 8u)
{
num = 3;
goto IL_4C;
}
break;
}
}
else
{
if (numberBase == 16u)
{
num = 4;
goto IL_4C;
}
if (numberBase == 32u)
{
num = 5;
goto IL_4C;
}
}
throw new InternalEvaluationException();
IL_4C:
int bitCount = this.BitCount;
int num2 = (bitCount + num - 1) / num;
int num3 = 0;
int num4 = num * (num2 - 1);
for (int i = 0; i < num; i++)
{
if (this.GetBit(num4++))
{
num3 += UInteger.power2[i];
}
}
char c = UInteger.digitChars[num3];
char[] array;
if (num3 >= 10)
{
array = new char[num2 + 1];
array[0] = '0';
array[1] = c;
}
else
{
array = new char[num2];
array[0] = c;
}
num4 = 0;
for (int j = 0; j < num2 - 1; j++)
{
int num5 = 0;
for (int k = 0; k < num; k++)
{
if (this.GetBit(num4++))
{
num5 += UInteger.power2[k];
}
}
array[array.Length - 1 - j] = UInteger.digitChars[num5];
}
return array;
}
private char[] ToStringGeneralBase(uint numberBase)
{
List<char> list = new List<char>(32);
UInteger dividend = this;
uint num;
do
{
dividend = UInteger.TinyDivMod(dividend, numberBase, out num);
list.Add(UInteger.digitChars[(int)((UIntPtr)num)]);
}
while (!dividend.IsZero);
if (num >= 10u)
{
list.Add('0');
}
list.Reverse();
return list.ToArray();
}
private char[] ToStringLargeBase(uint numberBase)
{
throw new NotImplementedException();
}
private static uint GetDigitFromChar(char c)
{
if (c > '9')
{
return (uint)(c - 'A' + '\n');
}
return (uint)(c - '0');
}
private char[] ToStringBase10()
{
while (true)
{
int num = UInteger.Base10Powers.Length - 2;
if (!(this > UInteger.Base10Powers[num]))
{
goto IL_54;
}
int num2 = (num + 2) * 2;
if (num2 > 2467)
{
num2 = 2467;
}
if (num2 <= UInteger.Base10Powers.Length)
{
break;
}
UInteger.CheckBase10Powers(num2);
}
throw new EvaluationException(EvaluationErrorCode.Overflow);
IL_54:
int num3 = 0;
int num4 = UInteger.Base10Powers.Length - 1;
do
{
int num5 = (num3 + num4) / 2;
if (this < UInteger.Base10Powers[num5])
{
num4 = num5;
}
else
{
num3 = num5;
}
}
while (num4 - num3 > 1);
char[] array = new char[num3 + 1];
UInteger n = this;
for (int i = num3; i >= 0; i--)
{
int num6 = 0;
UInteger m = UInteger.Base10Powers[i] << 3;
if (n >= m)
{
num6 += 8;
n -= m;
}
m = UInteger.Base10Powers[i] << 2;
if (n >= m)
{
num6 += 4;
n -= m;
}
m = UInteger.Base10Powers[i] << 1;
if (n >= m)
{
num6 += 2;
n -= m;
}
if (n >= UInteger.Base10Powers[i])
{
num6++;
n -= UInteger.Base10Powers[i];
}
if (num6 >= 10)
{
throw new InternalEvaluationException();
}
array[num3 - i] = (char)(48 + num6);
}
return array;
}
internal void WriteBinaryData(BinaryWriter bw)
{
if (this.data != null)
{
for (int i = 0; i < this.data.Length; i++)
{
bw.Write(this.data[i]);
}
}
}
public static UInteger operator <<(UInteger n, int s)
{
if (n.IsZero)
{
return Constants.ZeroUInt;
}
if (s == 0)
{
return n;
}
if (s == -2147483648)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
if (s < 0)
{
return n >> -s;
}
int num = s >> 5;
int num2 = s & 31;
if (num > 0 && num2 > 0)
{
return n.DwordShiftLeft(num).TinyShiftLeft(num2);
}
if (num > 0)
{
return n.DwordShiftLeft(num);
}
return n.TinyShiftLeft(num2);
}
public static UInteger operator >>(UInteger n, int s)
{
if (n.IsZero)
{
return Constants.ZeroUInt;
}
if (s == 0)
{
return n;
}
if (s == -2147483648)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
if (s < 0)
{
return n << -s;
}
int num = s >> 5;
int num2 = s & 31;
if (num > 0 && num2 > 0)
{
return n.DwordShiftRight(num).TinyShiftRight(num2);
}
if (num > 0)
{
return n.DwordShiftRight(num);
}
return n.TinyShiftRight(num2);
}
private UInteger DwordShiftLeft(int s)
{
if (s == 0 || this.IsZero)
{
return this;
}
uint[] array;
try
{
array = new uint[this.data.Length + s];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int i = 0; i < this.data.Length; i++)
{
array[i + s] = this.data[i];
}
return new UInteger(array);
}
private UInteger DwordShiftRight(int s)
{
if (s == 0 || this.IsZero)
{
return this;
}
if (this.data.Length < s)
{
return Constants.ZeroUInt;
}
uint[] array;
try
{
array = new uint[this.data.Length - s];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int i = 0; i < this.data.Length - s; i++)
{
array[i] = this.data[i + s];
}
return new UInteger(array);
}
private UInteger TinyShiftLeft(int s)
{
if (s == 0 || this.IsZero)
{
return this;
}
uint[] array;
try
{
array = new uint[this.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num = 0u;
for (int i = 0; i < this.data.Length; i++)
{
array[i] = (this.data[i] << s) + num;
num = this.data[i] >> 32 - s;
}
if (num == 0u)
{
return new UInteger(array);
}
return new UInteger(array, num);
}
private UInteger TinyShiftRight(int s)
{
if (s == 0 || this.IsZero)
{
return this;
}
uint[] array;
try
{
array = new uint[this.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num = 0u;
for (int i = this.data.Length - 1; i >= 0; i--)
{
array[i] = (this.data[i] >> s) + num;
num = this.data[i] << 32 - s;
}
return new UInteger(array);
}
public static UInteger operator *(UInteger n, uint v)
{
if (v == 0u || n.IsZero)
{
return Constants.ZeroUInt;
}
uint[] array;
try
{
array = new uint[n.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num = 0u;
for (int i = 0; i < n.data.Length; i++)
{
ulong num2 = (ulong)n.data[i] * (ulong)v + (ulong)num;
array[i] = (uint)num2;
num = (uint)(num2 >> 32);
}
if (num == 0u)
{
return new UInteger(array);
}
return new UInteger(array, num);
}
public static UInteger operator *(UInteger n, UInteger m)
{
if (n.IsZero || m.IsZero)
{
return Constants.ZeroUInt;
}
uint[] array;
try
{
array = new uint[n.data.Length + m.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int i = 0; i < n.data.Length; i++)
{
uint num = 0u;
for (int j = 0; j < m.data.Length; j++)
{
ulong num2 = (ulong)n.data[i] * (ulong)m.data[j] + (ulong)num;
uint num3 = (uint)num2;
num = (uint)(num2 >> 32);
array[i + j] += num3;
if (array[i + j] < num3)
{
num += 1u;
}
}
if (num != 0u)
{
array[i + m.data.Length] += num;
}
}
return new UInteger(array);
}
public static UInteger operator +(UInteger n, uint m)
{
if (m == 0u)
{
return n;
}
if (n.IsZero)
{
return new UInteger(m);
}
uint[] array;
try
{
array = new uint[n.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
array[0] = n.data[0] + m;
bool flag = array[0] >= m;
for (int i = 1; i < n.data.Length; i++)
{
array[i] = (flag ? n.data[i] : (n.data[i] + 1u));
flag = (flag || n.data[i] != 4294967295u);
}
if (!flag)
{
return new UInteger(array, 1u);
}
return new UInteger(array);
}
public static UInteger operator +(UInteger n, UInteger m)
{
if (n.IsZero)
{
return m;
}
if (m.IsZero)
{
return n;
}
int num = Math.Max(n.data.Length, m.data.Length);
uint[] array;
try
{
array = new uint[num];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num2 = 0u;
for (int i = 0; i < num; i++)
{
uint num3 = (i < n.data.Length) ? n.data[i] : 0u;
uint num4 = (i < m.data.Length) ? m.data[i] : 0u;
array[i] = num3 + num4 + num2;
num2 = ((array[i] < num3 || (num2 != 0u && array[i] <= num3)) ? 1u : 0u);
}
if (num2 == 0u)
{
return new UInteger(array);
}
return new UInteger(array, num2);
}
public static UInteger operator -(UInteger n, UInteger m)
{
if (m.IsZero)
{
return n;
}
uint[] array;
try
{
array = new uint[n.data.Length];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num = 0u;
for (int i = 0; i < n.data.Length; i++)
{
uint num2 = (i < m.data.Length) ? m.data[i] : 0u;
array[i] = n.data[i] - num2 - num;
num = ((n.data[i] < num2 || (num != 0u && n.data[i] == num2)) ? 1u : 0u);
}
return new UInteger(array);
}
public static uint operator %(UInteger n, uint m)
{
uint result;
UInteger.TinyDivMod(n, m, out result);
return result;
}
public static UInteger operator %(UInteger n, UInteger m)
{
UInteger result;
UInteger.DivMod(n, m, out result);
return result;
}
public static UInteger operator /(UInteger n, UInteger m)
{
UInteger uInteger;
return UInteger.DivMod(n, m, out uInteger);
}
public static UInteger Pow(UInteger root, uint power)
{
return UInteger.Pow(root, new UInteger(power));
}
public static UInteger Pow(UInteger root, UInteger power)
{
if (power.IsZero)
{
return Constants.OneUInt;
}
if (root.IsZero)
{
return Constants.ZeroUInt;
}
int bitCount = power.BitCount;
UInteger uInteger = Constants.OneUInt;
UInteger uInteger2 = root;
for (int i = 0; i < bitCount; i++)
{
if (power.GetBit(i))
{
uInteger *= uInteger2;
}
if (i < bitCount - 1)
{
uInteger2 *= uInteger2;
}
}
return uInteger;
}
public static UInteger PowMod(UInteger root, UInteger power, UInteger m)
{
if (m.IsOdd)
{
uint im = UInteger.NegInverseUInt32(m.LowestDword);
return UInteger.PowModImplMontgomery(root, power, m, im);
}
return UInteger.PowModImplMulMod(root, power, m);
}
private static UInteger PowModImplMulMod(UInteger root, UInteger power, UInteger m)
{
if (m.IsZero || m.IsOne)
{
throw new InternalEvaluationException();
}
if (power.IsZero)
{
return Constants.OneUInt;
}
if (root.IsZero)
{
return Constants.ZeroUInt;
}
int bitCount = power.BitCount;
UInteger uInteger = Constants.OneUInt;
UInteger uInteger2 = root;
for (int i = 0; i < bitCount; i++)
{
if (power.GetBit(i))
{
uInteger = uInteger * uInteger2 % m;
}
if (i < bitCount - 1)
{
uInteger2 = uInteger2 * uInteger2 % m;
}
}
return uInteger;
}
private static UInteger PowModImplMontgomery(UInteger root, UInteger power, UInteger m, uint im)
{
UInteger n = root << m.DwordCount * 32;
UInteger uInteger = n % m;
UInteger uInteger2 = Constants.OneUInt;
int bitCount = power.BitCount;
for (int i = 0; i < bitCount; i++)
{
if (uInteger.IsZero)
{
return Constants.ZeroUInt;
}
if (i > 0)
{
uInteger = UInteger.MontgomeryMul(uInteger, uInteger, m, im);
}
if (power.GetBit(i))
{
uInteger2 = UInteger.MontgomeryMul(uInteger2, uInteger, m, im);
}
}
return uInteger2;
}
private static uint NegInverseUInt32(uint m)
{
uint num = 1u;
uint num2 = 0u;
uint num3 = (uint)(4294967296uL / (ulong)m);
uint num4 = (uint)(4294967296uL - (ulong)(num3 * m));
uint num5 = num2 - num3 * num;
uint num6 = m;
m = num4;
num2 = num;
num = num5;
while (m != 0u)
{
num3 = num6 / m;
num4 = num6 - num3 * m;
num5 = num2 - num3 * num;
num6 = m;
m = num4;
num2 = num;
num = num5;
}
return 0u - num2;
}
private static UInteger MontgomeryMul(UInteger n1, UInteger n2, UInteger m, uint im)
{
UInteger uInteger = Constants.ZeroUInt;
int dwordCount = m.DwordCount;
for (int i = 0; i < dwordCount; i++)
{
uint num;
if (n1.DwordCount > i)
{
num = (uInteger.LowestDword + n1.data[i] * n2.LowestDword) * im;
if (n1.data[i] != 0u)
{
uInteger += n2 * n1.data[i];
}
}
else
{
num = uInteger.LowestDword * im;
}
if (num != 0u)
{
uInteger += m * num;
}
uInteger = uInteger.DwordShiftRight(1);
}
if (uInteger >= m)
{
uInteger -= m;
}
return uInteger;
}
public static UInteger Gcd(UInteger n, UInteger m)
{
if (n.IsZero)
{
return m;
}
if (m.IsZero)
{
return n;
}
int num = 0;
while (!n.GetBit(num) && !m.GetBit(num))
{
num++;
}
if (num > 0)
{
n >>= num;
m >>= num;
}
while (UInteger.Compare(n, m) != 0)
{
int num2 = 0;
while (!n.GetBit(num2))
{
num2++;
}
if (num2 > 0)
{
n >>= num2;
}
num2 = 0;
while (!m.GetBit(num2))
{
num2++;
}
if (num2 > 0)
{
m >>= num2;
}
int num3 = UInteger.Compare(n, m);
if (num3 < 0)
{
m -= n;
}
else
{
if (num3 > 0)
{
n -= m;
}
}
}
n <<= num;
return n;
}
public static UInteger Lcm(UInteger n, UInteger m)
{
if (n.IsZero || m.IsZero)
{
return Constants.ZeroUInt;
}
UInteger m2 = UInteger.Gcd(n, m);
if (m2.IsOne)
{
return n * m;
}
if (n.DwordCount > m.DwordCount)
{
return n / m2 * m;
}
return m / m2 * n;
}
public static UInteger DivMod(UInteger dividend, UInteger divisor, out UInteger remainder)
{
if (divisor.IsZero)
{
throw new EvaluationException(EvaluationErrorCode.DivideByZero);
}
if (dividend.IsZero)
{
remainder = Constants.ZeroUInt;
return Constants.ZeroUInt;
}
int num = UInteger.Compare(dividend, divisor);
if (num < 0)
{
remainder = dividend;
return Constants.ZeroUInt;
}
if (num == 0)
{
remainder = Constants.ZeroUInt;
return Constants.OneUInt;
}
if (divisor.data.Length == 1)
{
uint v;
UInteger result = UInteger.TinyDivMod(dividend, divisor.data[0], out v);
remainder = new UInteger(v);
return result;
}
ulong num2 = ((ulong)divisor.data[divisor.data.Length - 1] << 32) + (ulong)divisor.data[divisor.data.Length - 2];
uint num3;
for (num3 = (uint)(18446744073709551615uL / num2); num3 > 1u; num3 -= 1u)
{
UInteger uInteger = divisor * num3;
if (uInteger.data[uInteger.data.Length - 1] > 1u)
{
divisor = uInteger;
break;
}
}
if (num3 != 1u)
{
dividend *= num3;
}
uint num4 = divisor.data[divisor.data.Length - 1];
int i = dividend.data.Length - divisor.data.Length;
if (i > 0)
{
divisor = divisor.DwordShiftLeft(i);
}
uint[] array;
try
{
array = new uint[i + 1];
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
uint num5 = 0u;
int num6 = dividend.data.Length;
while (i >= 0)
{
uint num7;
if (num5 == num4)
{
num7 = 4294967295u;
}
else
{
uint num8 = (dividend.data != null && dividend.data.Length > num6 - 1) ? dividend.data[num6 - 1] : 0u;
num7 = (uint)((((ulong)num5 << 32) + (ulong)num8) / (ulong)num4);
}
UInteger uInteger2 = divisor * num7;
while (dividend < uInteger2)
{
num7 -= 1u;
uInteger2 -= divisor;
}
if (num7 > 0u)
{
array[i] = num7;
dividend -= uInteger2;
}
num5 = ((dividend.data != null && dividend.data.Length > num6 - 1) ? dividend.data[num6 - 1] : 0u);
num6--;
divisor = divisor.DwordShiftRight(1);
i--;
}
uint num9;
remainder = ((num3 == 1u) ? dividend : UInteger.TinyDivMod(dividend, num3, out num9));
return new UInteger(array);
}
public static UInteger TinyDivMod(UInteger dividend, uint divisor, out uint remainder)
{
if (divisor == 0u)
{
throw new EvaluationException(EvaluationErrorCode.DivideByZero);
}
if (dividend.IsZero)
{
remainder = 0u;
return dividend;
}
if (dividend.data.Length == 1)
{
uint num = dividend.data[0] / divisor;
remainder = dividend.data[0] - divisor * num;
return new UInteger(num);
}
uint[] array;
int num2;
try
{
if (dividend.data[dividend.data.Length - 1] < divisor)
{
array = new uint[dividend.data.Length - 1];
remainder = dividend.data[dividend.data.Length - 1];
num2 = dividend.data.Length - 2;
}
else
{
array = new uint[dividend.data.Length];
remainder = 0u;
num2 = dividend.data.Length - 1;
}
}
catch (OutOfMemoryException)
{
throw new EvaluationException(EvaluationErrorCode.Overflow);
}
for (int i = num2; i >= 0; i--)
{
ulong num3 = ((ulong)remainder << 32) + (ulong)dividend.data[i];
ulong num4 = num3 / (ulong)divisor;
array[i] = (uint)num4;
remainder = (uint)(num3 - num4 * (ulong)divisor);
}
return new UInteger(array);
}
public static bool operator ==(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) == 0;
}
public static bool operator !=(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) != 0;
}
public static bool operator <(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) < 0;
}
public static bool operator >(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) > 0;
}
public static bool operator <=(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) <= 0;
}
public static bool operator >=(UInteger n, UInteger m)
{
return UInteger.Compare(n, m) >= 0;
}
public override bool Equals(object obj)
{
return obj is UInteger && UInteger.Compare(this, (UInteger)obj) == 0;
}
public bool Equals(UInteger n)
{
return UInteger.Compare(this, n) == 0;
}
public override int GetHashCode()
{
return (int)this.LowestDword;
}
internal static int Compare(UInteger n, UInteger m)
{
if (n.data == null && m.data == null)
{
return 0;
}
if (n.data == null && m.data != null)
{
return -1;
}
if (n.data != null && m.data == null)
{
return 1;
}
if (n.data.Length < m.data.Length)
{
return -1;
}
if (n.data.Length > m.data.Length)
{
return 1;
}
for (int i = n.data.Length - 1; i >= 0; i--)
{
if (n.data[i] < m.data[i])
{
return -1;
}
if (n.data[i] > m.data[i])
{
return 1;
}
}
return 0;
}
public int CompareTo(UInteger n)
{
return UInteger.Compare(this, n);
}
public static bool operator ==(UInteger n, uint m)
{
return n.CompareWithUInt32(m) == 0;
}
public static bool operator !=(UInteger n, uint m)
{
return n.CompareWithUInt32(m) != 0;
}
public static bool operator <(UInteger n, uint m)
{
return n.CompareWithUInt32(m) < 0;
}
public static bool operator >(UInteger n, uint m)
{
return n.CompareWithUInt32(m) > 0;
}
public static bool operator <=(UInteger n, uint m)
{
return n.CompareWithUInt32(m) <= 0;
}
public static bool operator >=(UInteger n, uint m)
{
return n.CompareWithUInt32(m) >= 0;
}
private int CompareWithUInt32(uint m)
{
if (this.IsZero)
{
if (m != 0u)
{
return -1;
}
return 0;
}
else
{
if (this.data.Length > 1)
{
return 1;
}
if (this.data[0] == m)
{
return 0;
}
if (this.data[0] < m)
{
return -1;
}
return 1;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment