Created
September 14, 2013 08:12
-
-
Save chengluyu/6559869 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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