// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================================= ** ** Struct: BigInteger ** ** Purpose: Represents an arbitrary precision integer. ** =============================================================================*/ using System; using Contracts = System.Diagnostics.Debug; using Contract = System.Diagnostics.Debug; //using System.Globalization; // ReSharper disable InconsistentNaming // ReSharper disable once CheckNamespace namespace Numerics { #if !SILVERLIGHT [Serializable] #endif // !SILVERLIGHT internal struct BigInteger /*: IFormattable, IComparable, IComparable, IEquatable*/ { // ---- SECTION: members supporting exposed properties -------------* #region members supporting exposed properties private const uint kuMaskHighBit = unchecked((uint)int.MinValue); private const int kcbitUint = 32; //private const int kcbitUlong = 64; //private const int DecimalScaleFactorMask = 0x00FF0000; //private const int DecimalSignMask = unchecked((int)0x80000000); // For values int.MinValue < n <= int.MaxValue, the value is stored in sign // and _bits is null. For all other values, sign is +1 or -1 and the bits are in _bits private readonly int _sign; private readonly uint[] _bits; // We have to make a choice of how to represent int.MinValue. This is the one // value that fits in an int, but whose negation does not fit in an int. // We choose to use a large representation, so we're symmetric with respect to negation. private static readonly BigInteger s_bnMinInt = new BigInteger(-1, new[] { kuMaskHighBit }); private static readonly BigInteger s_bnOneInt = new BigInteger(1); private static readonly BigInteger s_bnZeroInt = new BigInteger(0); private static readonly BigInteger s_bnMinusOneInt = new BigInteger(-1); #if CONTRACTS_FULL [ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant((_bits == null) ? _sign > Int32.MinValue : ((_sign == 1 || _sign == -1) && Length(_bits) > 0)); Contract.Invariant(_bits == null || Length(_bits) > 1 || _bits[0] >= kuMaskHighBit , "One element array stores integers whose absolute value is between 0x80000000 and 0xFFFFFFFF"); } #endif [System.Diagnostics.Conditional("DEBUG")] private void AssertValid() { if (_bits != null) { Contracts.Assert(_sign == 1 || _sign == -1 /*, "_sign must be +1 or -1 when _bits is non-null"*/); Contracts.Assert(Length(_bits) > 0 /*, "_bits must contain at least 1 element or be null"*/); if (Length(_bits) == 1) Contracts.Assert(_bits[0] >= kuMaskHighBit /*, "Wasted space _bits[0] could have been packed into _sign"*/); } else Contracts.Assert(_sign > int.MinValue /*, "Int32.MinValue should not be stored in the _sign field"*/); } #endregion members supporting exposed properties // ---- SECTION: internal properties --------------* #region internal properties /*internal static BigInteger Zero { get { return s_bnZeroInt; } }*/ private static BigInteger One { get { return s_bnOneInt; } } /* internal static BigInteger MinusOne { get { return s_bnMinusOneInt; } } internal bool IsPowerOfTwo { get { AssertValid(); if (_bits == null) return (_sign & (_sign - 1)) == 0 && _sign != 0; if (_sign != 1) return false; int iu = Length(_bits) - 1; if ((_bits[iu] & (_bits[iu] - 1)) != 0) return false; while (--iu >= 0) { if (_bits[iu] != 0) return false; } return true; } } */ /* internal bool IsZero { get { AssertValid(); return _sign == 0; } } */ /* internal bool IsOne { get { AssertValid(); return _sign == 1 && _bits == null; } } */ private bool IsEven { get { AssertValid(); return _bits == null ? (_sign & 1) == 0 : (_bits[0] & 1) == 0; } } private int Sign { get { AssertValid(); return (_sign >> (kcbitUint - 1)) - (-_sign >> (kcbitUint - 1)); } } #endregion internal properties // ---- SECTION: internal instance methods --------------* #region internal instance methods public override bool Equals(object obj) { AssertValid(); if (!(obj is BigInteger)) return false; return Equals((BigInteger)obj); } public override int GetHashCode() { AssertValid(); // ReSharper disable NonReadonlyMemberInGetHashCode if (_bits == null) return _sign; var hash = _sign; for (var iv = Length(_bits); --iv >= 0; ) hash = NumericsHelpers.CombineHash(hash, (int)_bits[iv]); return hash; } /*public bool Equals(Int64 other) { AssertValid(); if (_bits == null) return _sign == other; int cu; if ((_sign ^ other) < 0 || (cu = Length(_bits)) > 2) return false; var uu = other < 0 ? (ulong)-other : (ulong)other; if (cu == 1) return _bits[0] == uu; return NumericsHelpers.MakeUlong(_bits[1], _bits[0]) == uu; } public bool Equals(UInt64 other) { AssertValid(); if (_sign < 0) return false; if (_bits == null) return (ulong)_sign == other; var cu = Length(_bits); if (cu > 2) return false; if (cu == 1) return _bits[0] == other; return NumericsHelpers.MakeUlong(_bits[1], _bits[0]) == other; }*/ /*public bool Equals(BigInteger other) { AssertValid(); other.AssertValid(); if (_sign != other._sign) return false; if (_bits == other._bits) // _sign == other._sign && _bits == null && other._bits == null return true; if (_bits == null || other._bits == null) return false; var cu = Length(_bits); if (cu != Length(other._bits)) return false; var cuDiff = GetDiffLength(_bits, other._bits, cu); return cuDiff == 0; }*/ /*internal int CompareTo(Int64 other) { AssertValid(); if (_bits == null) return ((long)_sign).CompareTo(other); int cu; if ((_sign ^ other) < 0 || (cu = Length(_bits)) > 2) return _sign; var uu = other < 0 ? (ulong)-other : (ulong)other; var uuTmp = cu == 2 ? NumericsHelpers.MakeUlong(_bits[1], _bits[0]) : _bits[0]; return _sign * uuTmp.CompareTo(uu); } internal int CompareTo(UInt64 other) { AssertValid(); if (_sign < 0) return -1; if (_bits == null) return ((ulong)_sign).CompareTo(other); var cu = Length(_bits); if (cu > 2) return +1; var uuTmp = cu == 2 ? NumericsHelpers.MakeUlong(_bits[1], _bits[0]) : _bits[0]; return uuTmp.CompareTo(other); }*/ private int CompareTo(BigInteger other) { AssertValid(); other.AssertValid(); if ((_sign ^ other._sign) < 0) { // Different signs, so the comparison is easy. return _sign < 0 ? -1 : +1; } // Same signs if (_bits == null) { if (other._bits == null) return _sign < other._sign ? -1 : _sign > other._sign ? +1 : 0; return -other._sign; } int cuThis, cuOther; if (other._bits == null || (cuThis = Length(_bits)) > (cuOther = Length(other._bits))) return _sign; if (cuThis < cuOther) return -_sign; var cuDiff = GetDiffLength(_bits, other._bits, cuThis); if (cuDiff == 0) return 0; return _bits[cuDiff - 1] < other._bits[cuDiff - 1] ? -_sign : _sign; } /* public int CompareTo(Object obj) { if (obj == null) return 1; if (!(obj is BigInteger)) throw new ArgumentException("Argument must be BigInteger", "obj"); return CompareTo((BigInteger)obj); } */ // Return the value of this BigInteger as a little-endian twos-complement // byte array, using the fewest number of bytes possible. If the value is zero, // return an array of one byte whose element is 0x00. internal byte[] ToByteArray() { if (_bits == null && _sign == 0) return new byte[] { 0 }; // We could probably make this more efficient by eliminating one of the passes. // The current code does one pass for uint array -> byte array conversion, // and then another pass to remove unneeded bytes at the top of the array. uint[] dwords; byte highByte; if (_bits == null) { dwords = new[] { (uint)_sign }; highByte = (byte)(_sign < 0 ? 0xff : 0x00); } else if (_sign == -1) { dwords = (uint[])_bits.Clone(); NumericsHelpers.DangerousMakeTwosComplement(dwords); // mutates dwords highByte = 0xff; } else { dwords = _bits; highByte = 0x00; } var bytes = new byte[checked(4 * dwords.Length)]; var curByte = 0; foreach (var t in dwords) { var dword = t; for (var j = 0; j < 4; j++) { bytes[curByte++] = (byte)(dword & 0xff); dword >>= 8; } } // ensure high bit is 0 if positive, 1 if negative if ((bytes[bytes.Length - 1] & 0x80) == (highByte & 0x80)) return bytes; var trimmedBytes = new byte[bytes.Length + 1]; Array.Copy(bytes, trimmedBytes, bytes.Length); trimmedBytes[trimmedBytes.Length - 1] = highByte; return trimmedBytes; } // Return the value of this BigInteger as a little-endian twos-complement // uint array, using the fewest number of uints possible. If the value is zero, // return an array of one uint whose element is 0. /* private UInt32[] ToUInt32Array() { if (_bits == null && _sign == 0) return new uint[] { 0 }; uint[] dwords; uint highDWord; if (_bits == null) { dwords = new[] { (uint)_sign }; highDWord = _sign < 0 ? UInt32.MaxValue : 0; } else if (_sign == -1) { dwords = (uint[])_bits.Clone(); NumericsHelpers.DangerousMakeTwosComplement(dwords); // mutates dwords highDWord = UInt32.MaxValue; } else { dwords = _bits; highDWord = 0; } // find highest significant byte int msb; for (msb = dwords.Length - 1; msb > 0; msb--) { if (dwords[msb] != highDWord) break; } // ensure high bit is 0 if positive, 1 if negative var needExtraByte = (dwords[msb] & 0x80000000) != (highDWord & 0x80000000); var trimmed = new uint[msb + 1 + (needExtraByte ? 1 : 0)]; Array.Copy(dwords, trimmed, msb + 1); if (needExtraByte) trimmed[trimmed.Length - 1] = highDWord; return trimmed; } */ /*public override String ToString() { return BigNumber.FormatBigInteger(this, null, NumberFormatInfo.CurrentInfo); } internal String ToString(IFormatProvider provider) { return BigNumber.FormatBigInteger(this, null, NumberFormatInfo.GetInstance(provider)); } internal String ToString(String format) { return BigNumber.FormatBigInteger(this, format, NumberFormatInfo.CurrentInfo); } public String ToString(String format, IFormatProvider provider) { return BigNumber.FormatBigInteger(this, format, NumberFormatInfo.GetInstance(provider)); }*/ #endregion internal instance methods // -------- SECTION: constructors -----------------* #region constructors private BigInteger(int value) { if (value == Int32.MinValue) this = s_bnMinInt; else { _sign = value; _bits = null; } AssertValid(); } /* internal BigInteger(uint value) { if (value <= Int32.MaxValue) { _sign = (int)value; _bits = null; } else { _sign = +1; _bits = new uint[1]; _bits[0] = value; } AssertValid(); } */ /* internal BigInteger(Int64 value) { if (Int32.MinValue <= value && value <= Int32.MaxValue) { if (value == Int32.MinValue) this = s_bnMinInt; else { _sign = (int)value; _bits = null; } AssertValid(); return; } ulong x; if (value < 0) { x = (ulong)-value; _sign = -1; } else { Contract.Assert(value != 0); x = (ulong)value; _sign = +1; } _bits = new uint[2]; _bits[0] = (uint)x; _bits[1] = (uint)(x >> kcbitUint); AssertValid(); } */ /* internal BigInteger(UInt64 value) { if (value <= Int32.MaxValue) { _sign = (int)value; _bits = null; } else { _sign = +1; _bits = new uint[2]; _bits[0] = (uint)value; _bits[1] = (uint)(value >> kcbitUint); } AssertValid(); } */ /*internal BigInteger(Single value) { if (Single.IsInfinity(value)) throw new OverflowException("Overflow BigIntInfinity"); if (Single.IsNaN(value)) throw new OverflowException("Overflow not a number"); ////Contract.EndContractBlock(); _sign = 0; _bits = null; // ReSharper disable once ExpressionIsAlwaysNull SetBitsFromDouble(value); AssertValid(); } internal BigInteger(Double value) { if (Double.IsInfinity(value)) throw new OverflowException("Overflow BigIntInfinity"); if (Double.IsNaN(value)) throw new OverflowException("Overflow not a number"); ////Contract.EndContractBlock(); _sign = 0; _bits = null; // ReSharper disable once ExpressionIsAlwaysNull SetBitsFromDouble(value); AssertValid(); }*/ /*internal BigInteger(Decimal value) { // First truncate to get scale to 0 and extract bits var bits = Decimal.GetBits(Decimal.Truncate(value)); Contract.Assert(bits.Length == 4 && (bits[3] & DecimalScaleFactorMask) == 0); var size = 3; while (size > 0 && bits[size - 1] == 0) size--; if (size == 0) { this = s_bnZeroInt; } else if (size == 1 && bits[0] > 0) { // bits[0] is the absolute value of this decimal // if bits[0] < 0 then it is too large to be packed into _sign _sign = bits[0]; _sign *= (bits[3] & DecimalSignMask) != 0 ? -1 : +1; _bits = null; } else { _bits = new UInt32[size]; _bits[0] = (UInt32)bits[0]; if (size > 1) _bits[1] = (UInt32)bits[1]; if (size > 2) _bits[2] = (UInt32)bits[2]; _sign = (bits[3] & DecimalSignMask) != 0 ? -1 : +1; } AssertValid(); }*/ // // Create a BigInteger from a little-endian twos-complement byte array // internal BigInteger(Byte[] value) { if (value == null) throw new ArgumentNullException("value"); //Contract.EndContractBlock(); var byteCount = value.Length; var isNegative = byteCount > 0 && ((value[byteCount - 1] & 0x80) == 0x80); // Try to conserve space as much as possible by checking for wasted leading byte[] entries while (byteCount > 0 && value[byteCount - 1] == 0) byteCount--; if (byteCount == 0) { // BigInteger.Zero _sign = 0; _bits = null; // ReSharper disable once ExpressionIsAlwaysNull AssertValid(); return; } if (byteCount <= 4) { if (isNegative) _sign = unchecked((int)0xffffffff); else _sign = 0; for (var i = byteCount - 1; i >= 0; i--) { _sign <<= 8; _sign |= value[i]; } _bits = null; if (_sign < 0 && !isNegative) { // int32 overflow // example: Int64 value 2362232011 (0xCB, 0xCC, 0xCC, 0x8C, 0x0) // can be naively packed into 4 bytes (due to the leading 0x0) // it overflows into the int32 sign bit _bits = new uint[1]; _bits[0] = (uint)_sign; _sign = +1; } if (_sign == Int32.MinValue) this = s_bnMinInt; } else { var unalignedBytes = byteCount % 4; var dwordCount = byteCount / 4 + (unalignedBytes == 0 ? 0 : 1); var isZero = true; var val = new uint[dwordCount]; // Copy all dwords, except but don't do the last one if it's not a full four bytes int curDword; var curByte = 3; for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) { var byteInDword = 0; while (byteInDword < 4) { if (value[curByte] != 0x00) isZero = false; val[curDword] <<= 8; val[curDword] |= value[curByte]; curByte--; byteInDword++; } curByte += 8; } // Copy the last dword specially if it's not aligned if (unalignedBytes != 0) { if (isNegative) val[dwordCount - 1] = 0xffffffff; for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) { if (value[curByte] != 0x00) isZero = false; val[curDword] <<= 8; val[curDword] |= value[curByte]; } } if (isZero) { this = s_bnZeroInt; } else if (isNegative) { NumericsHelpers.DangerousMakeTwosComplement(val); // mutates val // pack _bits to remove any wasted space after the twos complement var len = val.Length; while (len > 0 && val[len - 1] == 0) len--; if (len == 1 && (int)val[0] > 0) { if (val[0] == 1 /* abs(-1) */) { this = s_bnMinusOneInt; } else if (val[0] == kuMaskHighBit /* abs(Int32.MinValue) */) //TODO: V3022 https://www.viva64.com/en/w/V3022 Expression 'val[0] == kuMaskHighBit' is always false. { this = s_bnMinInt; } else { _sign = -1 * (int)val[0]; _bits = null; } } else if (len != val.Length) { _sign = -1; _bits = new uint[len]; Array.Copy(val, _bits, len); } else { _sign = -1; _bits = val; } } else { _sign = +1; _bits = val; } } AssertValid(); } internal BigInteger(int n, uint[] rgu) { _sign = n; _bits = rgu; AssertValid(); } // // BigInteger(uint[] value, bool negative) // // Constructor used during bit manipulation and arithmetic // // The uint[] value is expected to be the absolute value of the number // with the bool negative indicating the Sign of the value. // // When possible the uint[] will be packed into _sign to conserve space // /* internal BigInteger(uint[] value, bool negative) { if (value == null) throw new ArgumentNullException("value"); //Contract.EndContractBlock(); int len; // Try to conserve space as much as possible by checking for wasted leading uint[] entries // sometimes the uint[] has leading zeros from bit manipulation operations & and ^ for (len = value.Length; len > 0 && value[len - 1] == 0; len--) { } if (len == 0) this = s_bnZeroInt; // values like (Int32.MaxValue+1) are stored as "0x80000000" and as such cannot be packed into _sign else if (len == 1 && value[0] < kuMaskHighBit) { _sign = negative ? -(int)value[0] : (int)value[0]; _bits = null; // Although Int32.MinValue fits in _sign, we represent this case differently for negate if (_sign == Int32.MinValue) this = s_bnMinInt; } else { _sign = negative ? -1 : +1; _bits = new uint[len]; Array.Copy(value, _bits, len); } AssertValid(); } */ // // Create a BigInteger from a little-endian twos-complement UInt32 array // When possible, value is assigned directly to this._bits without an array copy // so use this ctor with care // // private BigInteger(uint[] value) // { // if (value == null) // throw new ArgumentNullException("value"); // // var dwordCount = value.Length; // var isNegative = dwordCount > 0 && ((value[dwordCount - 1] & 0x80000000) == 0x80000000); // // // Try to conserve space as much as possible by checking for wasted leading uint[] entries // while (dwordCount > 0 && value[dwordCount - 1] == 0) dwordCount--; // // if (dwordCount == 0) // { // // BigInteger.Zero // this = s_bnZeroInt; // AssertValid(); // return; // } // if (dwordCount == 1) // { // if ((int)value[0] < 0 && !isNegative) // { // _bits = new uint[1]; // _bits[0] = value[0]; // _sign = +1; // } // // handle the special cases where the BigInteger likely fits into _sign // else if (Int32.MinValue == (int)value[0]) // { // this = s_bnMinInt; // } // else // { // _sign = (int)value[0]; // _bits = null; // } // AssertValid(); // return; // } // // if (!isNegative) // { // // handle the simple postive value cases where the input is already in sign magnitude // if (dwordCount != value.Length) // { // _sign = +1; // _bits = new uint[dwordCount]; // Array.Copy(value, _bits, dwordCount); // } // // no trimming is possible. Assign value directly to _bits. // else // { // _sign = +1; // _bits = value; // } // AssertValid(); // return; // } // // // // finally handle the more complex cases where we must transform the input into sign magnitude // NumericsHelpers.DangerousMakeTwosComplement(value); // mutates val // // // pack _bits to remove any wasted space after the twos complement // var len = value.Length; // while (len > 0 && value[len - 1] == 0) len--; // // // the number is represented by a single dword // if (len == 1 && (int)value[0] > 0) // { // if (value[0] == 1 /* abs(-1) */) // { // this = s_bnMinusOneInt; // } // else if (value[0] == kuMaskHighBit /* abs(Int32.MinValue) */) // { // this = s_bnMinInt; // } // else // { // _sign = -1 * (int)value[0]; // _bits = null; // } // } // // the number is represented by multiple dwords // // trim off any wasted uint values when possible // else if (len != value.Length) // { // _sign = -1; // _bits = new uint[len]; // Array.Copy(value, _bits, len); // } // // no trimming is possible. Assign value directly to _bits. // else // { // _sign = -1; // _bits = value; // } // AssertValid(); // } #endregion constructors // -------- SECTION: internal static methods -----------------* #region internal static methods #if !SILVERLIGHT || FEATURE_NETCORE /* internal static BigInteger Parse(String value) { return BigNumber.ParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } */ /* internal static BigInteger Parse(String value, NumberStyles style) { return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.CurrentInfo); } */ /* internal static BigInteger Parse(String value, IFormatProvider provider) { return BigNumber.ParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } */ /* internal static BigInteger Parse(String value, NumberStyles style, IFormatProvider provider) { return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider)); } */ /* internal static Boolean TryParse(String value, out BigInteger result) { return BigNumber.TryParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } */ /* internal static Boolean TryParse(String value, NumberStyles style, IFormatProvider provider, out BigInteger result) { return BigNumber.TryParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider), out result); } */ #endif //!SILVERLIGHT || FEATURE_NETCORE /* internal static Int32 Compare(BigInteger left, BigInteger right) { return left.CompareTo(right); } */ /* internal static BigInteger Abs(BigInteger value) { return value >= Zero ? value : -value; } */ /* internal static BigInteger Add(BigInteger left, BigInteger right) { return left + right; } */ /* internal static BigInteger Subtract(BigInteger left, BigInteger right) { return left - right; } */ /* internal static BigInteger Multiply(BigInteger left, BigInteger right) { return left * right; } */ /* internal static BigInteger Divide(BigInteger dividend, BigInteger divisor) { return dividend / divisor; } */ /* internal static BigInteger Remainder(BigInteger dividend, BigInteger divisor) { return dividend % divisor; } */ /* internal static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out BigInteger remainder) { dividend.AssertValid(); divisor.AssertValid(); var signNum = +1; var signDen = +1; var regNum = new BigIntegerBuilder(dividend, ref signNum); var regDen = new BigIntegerBuilder(divisor, ref signDen); var regQuo = new BigIntegerBuilder(); // regNum and regQuo are overwritten with the remainder and quotient, respectively regNum.ModDiv(ref regDen, ref regQuo); remainder = regNum.GetInteger(signNum); return regQuo.GetInteger(signNum * signDen); } */ /* internal static BigInteger Negate(BigInteger value) { return -value; } */ // Returns the natural (base e) logarithm of a specified number. /* internal static Double Log(BigInteger value, Double baseValue = Math.E) { // ReSharper disable CompareOfFloatsByEqualityOperator if (value._sign < 0 || baseValue == 1.0D) return Double.NaN; if (baseValue == Double.PositiveInfinity) return value.IsOne ? 0.0D : Double.NaN; if (baseValue == 0.0D && !value.IsOne) return Double.NaN; if (value._bits == null) return Math.Log(value._sign, baseValue); // ReSharper restore CompareOfFloatsByEqualityOperator Double c = 0, d = 0.5D; const Double log2 = 0.69314718055994529D; var uintLength = Length(value._bits); var topbits = BitLengthOfUInt(value._bits[uintLength - 1]); var bitlen = (uintLength - 1) * kcbitUint + topbits; var indbit = (uint)(1 << (topbits - 1)); for (var index = uintLength - 1; index >= 0; --index) { while (indbit != 0) { if ((value._bits[index] & indbit) != 0) c += d; d *= 0.5; indbit >>= 1; } indbit = 0x80000000; } return (Math.Log(c) + log2 * bitlen) / Math.Log(baseValue); } */ /* internal static Double Log10(BigInteger value) { return Log(value, 10); } */ /* internal static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right) { left.AssertValid(); right.AssertValid(); // gcd(0, 0) = 0 // gcd(a, 0) = |a|, for a != 0, since any number is a divisor of 0, and the greatest divisor of a is |a| if (left._sign == 0) return Abs(right); if (right._sign == 0) return Abs(left); var reg1 = new BigIntegerBuilder(left); var reg2 = new BigIntegerBuilder(right); BigIntegerBuilder.GCD(ref reg1, ref reg2); return reg1.GetInteger(+1); } */ /* internal static BigInteger Max(BigInteger left, BigInteger right) { if (left.CompareTo(right) < 0) return right; return left; } */ /* internal static BigInteger Min(BigInteger left, BigInteger right) { if (left.CompareTo(right) <= 0) return left; return right; } */ private static void ModPowUpdateResult(ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) { NumericsHelpers.Swap(ref regRes, ref regTmp); regRes.Mul(ref regTmp, ref regVal); // result = result * value; regRes.Mod(ref regMod); // result = result % modulus; } private static void ModPowSquareModValue(ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) { NumericsHelpers.Swap(ref regVal, ref regTmp); regVal.Mul(ref regTmp, ref regTmp); // value = value * value; regVal.Mod(ref regMod); // value = value % modulus; } private static void ModPowInner(uint exp, ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) { while (exp != 0) // !(Exponent.IsZero) { if ((exp & 1) == 1) // !(Exponent.IsEven) ModPowUpdateResult(ref regRes, ref regVal, ref regMod, ref regTmp); if (exp == 1) // Exponent.IsOne - we can exit early break; ModPowSquareModValue(ref regVal, ref regMod, ref regTmp); exp >>= 1; } } private static void ModPowInner32(uint exp, ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) { for (var i = 0; i < 32; i++) { if ((exp & 1) == 1) // !(Exponent.IsEven) ModPowUpdateResult(ref regRes, ref regVal, ref regMod, ref regTmp); ModPowSquareModValue(ref regVal, ref regMod, ref regTmp); exp >>= 1; } } internal static BigInteger ModPow(BigInteger value, BigInteger exponent, BigInteger modulus) { if (exponent.Sign < 0) throw new ArgumentOutOfRangeException("exponent", "ArgumentOutOfRange must be non negative"); //Contract.EndContractBlock(); value.AssertValid(); exponent.AssertValid(); modulus.AssertValid(); var signRes = +1; var signVal = +1; var signMod = +1; var expIsEven = exponent.IsEven; var regRes = new BigIntegerBuilder(One, ref signRes); var regVal = new BigIntegerBuilder(value, ref signVal); var regMod = new BigIntegerBuilder(modulus, ref signMod); var regTmp = new BigIntegerBuilder(regVal.Size); regRes.Mod(ref regMod); // Handle special case of exponent=0, modulus=1 if (exponent._bits == null) { // exponent fits into an Int32 ModPowInner((uint)exponent._sign, ref regRes, ref regVal, ref regMod, ref regTmp); } else { // very large exponent var len = Length(exponent._bits); for (var i = 0; i < len - 1; i++) { var exp = exponent._bits[i]; ModPowInner32(exp, ref regRes, ref regVal, ref regMod, ref regTmp); } ModPowInner(exponent._bits[len - 1], ref regRes, ref regVal, ref regMod, ref regTmp); } return regRes.GetInteger(value._sign > 0 ? +1 : expIsEven ? +1 : -1); } /* internal static BigInteger Pow(BigInteger value, Int32 exponent) { if (exponent < 0) throw new ArgumentOutOfRangeException("exponent", "ArgumentOutOfRange must be non negative"); //Contract.EndContractBlock(); value.AssertValid(); if (exponent == 0) return One; if (exponent == 1) return value; if (value._bits == null) { if (value._sign == 1) return value; if (value._sign == -1) return (exponent & 1) != 0 ? value : 1; if (value._sign == 0) return value; } var sign = +1; var regSquare = new BigIntegerBuilder(value, ref sign); // Get an estimate of the size needed for regSquare and regRes, so we can minimize allocations. var cuSquareMin = regSquare.Size; var cuSquareMax = cuSquareMin; var uSquareMin = regSquare.High; var uSquareMax = uSquareMin + 1; if (uSquareMax == 0) { cuSquareMax++; uSquareMax = 1; } var cuResMin = 1; var cuResMax = 1; uint uResMin = 1; uint uResMax = 1; for (var expTmp = exponent; ; ) { if ((expTmp & 1) != 0) { MulUpper(ref uResMax, ref cuResMax, uSquareMax, cuSquareMax); MulLower(ref uResMin, ref cuResMin, uSquareMin, cuSquareMin); } if ((expTmp >>= 1) == 0) break; MulUpper(ref uSquareMax, ref cuSquareMax, uSquareMax, cuSquareMax); MulLower(ref uSquareMin, ref cuSquareMin, uSquareMin, cuSquareMin); } if (cuResMax > 1) regSquare.EnsureWritable(cuResMax, 0); var regTmp = new BigIntegerBuilder(cuResMax); var regRes = new BigIntegerBuilder(cuResMax); regRes.Set(1); if ((exponent & 1) == 0) sign = +1; for (var expTmp = exponent; ; ) { if ((expTmp & 1) != 0) { NumericsHelpers.Swap(ref regRes, ref regTmp); regRes.Mul(ref regSquare, ref regTmp); } if ((expTmp >>= 1) == 0) break; NumericsHelpers.Swap(ref regSquare, ref regTmp); regSquare.Mul(ref regTmp, ref regTmp); } return regRes.GetInteger(sign); } */ #endregion internal static methods // -------- SECTION: internal static operators -----------------* #region internal static operators /*public static implicit operator BigInteger(Byte value) { return new BigInteger(value); } public static implicit operator BigInteger(SByte value) { return new BigInteger(value); } public static implicit operator BigInteger(Int16 value) { return new BigInteger(value); } public static implicit operator BigInteger(UInt16 value) { return new BigInteger(value); } public static implicit operator BigInteger(int value) { return new BigInteger(value); } public static implicit operator BigInteger(uint value) { return new BigInteger(value); } public static implicit operator BigInteger(long value) { return new BigInteger(value); } public static implicit operator BigInteger(ulong value) { return new BigInteger(value); }*/ /*public static explicit operator BigInteger(Single value) { return new BigInteger(value); } public static explicit operator BigInteger(Double value) { return new BigInteger(value); } public static explicit operator BigInteger(Decimal value) { return new BigInteger(value); } public static explicit operator Byte(BigInteger value) { return checked((byte)(int)value); } public static explicit operator SByte(BigInteger value) { return checked((sbyte)(int)value); } public static explicit operator Int16(BigInteger value) { return checked((short)(int)value); } public static explicit operator UInt16(BigInteger value) { return checked((ushort)(int)value); } public static explicit operator Int32(BigInteger value) { value.AssertValid(); if (value._bits == null) { return value._sign; // value packed into int32 sign } else if (Length(value._bits) > 1) { // more than 32 bits throw new OverflowException("Overflow Int32"); } else if (value._sign > 0) { return checked((int)value._bits[0]); } else { if (value._bits[0] > kuMaskHighBit) { // value > Int32.MinValue throw new OverflowException("Overflow Int32"); } return unchecked(-(int)value._bits[0]); } } public static explicit operator UInt32(BigInteger value) { value.AssertValid(); if (value._bits == null) { return checked((uint)value._sign); } else if (Length(value._bits) > 1 || value._sign < 0) { throw new OverflowException("Overflow UInt32"); } else { return value._bits[0]; } } public static explicit operator Int64(BigInteger value) { value.AssertValid(); if (value._bits == null) { return value._sign; } var len = Length(value._bits); if (len > 2) { throw new OverflowException("Overflow Int64"); } var uu = len > 1 ? NumericsHelpers.MakeUlong(value._bits[1], value._bits[0]) : value._bits[0]; var ll = value._sign > 0 ? (long)uu : -(long)uu; if ((ll > 0 && value._sign > 0) || (ll < 0 && value._sign < 0)) { // signs match, no overflow return ll; } throw new OverflowException("Overflow Int64"); } public static explicit operator UInt64(BigInteger value) { value.AssertValid(); if (value._bits == null) { return checked((ulong)value._sign); } var len = Length(value._bits); if (len > 2 || value._sign < 0) { throw new OverflowException("Overflow UInt64"); } if (len > 1) { return NumericsHelpers.MakeUlong(value._bits[1], value._bits[0]); } else { return value._bits[0]; } }*/ /*public static explicit operator Single(BigInteger value) { return (Single)(Double)value; }*/ /*public static explicit operator Double(BigInteger value) { value.AssertValid(); if (value._bits == null) return value._sign; ulong man; int exp; var sign = +1; var reg = new BigIntegerBuilder(value, ref sign); reg.GetApproxParts(out exp, out man); return NumericsHelpers.GetDoubleFromParts(sign, exp, man); } public static explicit operator Decimal(BigInteger value) { value.AssertValid(); if (value._bits == null) return value._sign; var length = Length(value._bits); if (length > 3) throw new OverflowException("Overflow Decimal"); int lo = 0, mi = 0, hi = 0; if (length > 2) hi = (Int32)value._bits[2]; if (length > 1) mi = (Int32)value._bits[1]; if (length > 0) lo = (Int32)value._bits[0]; return new Decimal(lo, mi, hi, value._sign < 0, 0); } public static BigInteger operator &(BigInteger left, BigInteger right) { if (left.IsZero || right.IsZero) { return Zero; } var x = left.ToUInt32Array(); var y = right.ToUInt32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu & yu; } return new BigInteger(z); } public static BigInteger operator |(BigInteger left, BigInteger right) { if (left.IsZero) return right; if (right.IsZero) return left; var x = left.ToUInt32Array(); var y = right.ToUInt32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu | yu; } return new BigInteger(z); } public static BigInteger operator ^(BigInteger left, BigInteger right) { var x = left.ToUInt32Array(); var y = right.ToUInt32Array(); var z = new uint[Math.Max(x.Length, y.Length)]; var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; for (var i = 0; i < z.Length; i++) { var xu = i < x.Length ? x[i] : xExtend; var yu = i < y.Length ? y[i] : yExtend; z[i] = xu ^ yu; } return new BigInteger(z); } public static BigInteger operator <<(BigInteger value, int shift) { if (shift == 0) return value; else if (shift == Int32.MinValue) return value >> Int32.MaxValue >> 1; else if (shift < 0) return value >> -shift; var digitShift = shift / kcbitUint; var smallShift = shift - digitShift * kcbitUint; uint[] xd; int xl; var negx = GetPartsForBitManipulation(ref value, out xd, out xl); var zl = xl + digitShift + 1; var zd = new uint[zl]; if (smallShift == 0) { for (var i = 0; i < xl; i++) { zd[i + digitShift] = xd[i]; } } else { var carryShift = kcbitUint - smallShift; uint carry = 0; int i; for (i = 0; i < xl; i++) { var rot = xd[i]; zd[i + digitShift] = rot << smallShift | carry; carry = rot >> carryShift; } zd[i + digitShift] = carry; } return new BigInteger(zd, negx); } public static BigInteger operator >>(BigInteger value, int shift) { if (shift == 0) return value; else if (shift == Int32.MinValue) return value << Int32.MaxValue << 1; else if (shift < 0) return value << -shift; var digitShift = shift / kcbitUint; var smallShift = shift - digitShift * kcbitUint; uint[] xd; int xl; var negx = GetPartsForBitManipulation(ref value, out xd, out xl); if (negx) { if (shift >= kcbitUint * xl) { return MinusOne; } var temp = new uint[xl]; Array.Copy(xd , temp , xl ); // make a copy of immutable value._bits xd = temp; NumericsHelpers.DangerousMakeTwosComplement(xd); // mutates xd } var zl = xl - digitShift; if (zl < 0) zl = 0; var zd = new uint[zl]; if (smallShift == 0) { for (var i = xl - 1; i >= digitShift; i--) { zd[i - digitShift] = xd[i]; } } else { var carryShift = kcbitUint - smallShift; uint carry = 0; for (var i = xl - 1; i >= digitShift; i--) { var rot = xd[i]; if (negx && i == xl - 1) // sign-extend the first shift for negative ints then let the carry propagate zd[i - digitShift] = (rot >> smallShift) | (0xFFFFFFFF << carryShift); else zd[i - digitShift] = (rot >> smallShift) | carry; carry = rot << carryShift; } } if (negx) { NumericsHelpers.DangerousMakeTwosComplement(zd); // mutates zd } return new BigInteger(zd, negx); } public static BigInteger operator ~(BigInteger value) { return -(value + One); } public static BigInteger operator -(BigInteger value) { value.AssertValid(); value._sign = -value._sign; value.AssertValid(); return value; } public static BigInteger operator +(BigInteger value) { value.AssertValid(); return value; } public static BigInteger operator ++(BigInteger value) { return value + One; } public static BigInteger operator --(BigInteger value) { return value - One; } public static BigInteger operator +(BigInteger left, BigInteger right) { left.AssertValid(); right.AssertValid(); if (right.IsZero) return left; if (left.IsZero) return right; var sign1 = +1; var sign2 = +1; var reg1 = new BigIntegerBuilder(left, ref sign1); var reg2 = new BigIntegerBuilder(right, ref sign2); if (sign1 == sign2) reg1.Add(ref reg2); else reg1.Sub(ref sign1, ref reg2); return reg1.GetInteger(sign1); } public static BigInteger operator -(BigInteger left, BigInteger right) { left.AssertValid(); right.AssertValid(); if (right.IsZero) return left; if (left.IsZero) return -right; var sign1 = +1; var sign2 = -1; var reg1 = new BigIntegerBuilder(left, ref sign1); var reg2 = new BigIntegerBuilder(right, ref sign2); if (sign1 == sign2) reg1.Add(ref reg2); else reg1.Sub(ref sign1, ref reg2); return reg1.GetInteger(sign1); } public static BigInteger operator *(BigInteger left, BigInteger right) { left.AssertValid(); right.AssertValid(); var sign = +1; var reg1 = new BigIntegerBuilder(left, ref sign); var reg2 = new BigIntegerBuilder(right, ref sign); reg1.Mul(ref reg2); return reg1.GetInteger(sign); } public static BigInteger operator /(BigInteger dividend, BigInteger divisor) { dividend.AssertValid(); divisor.AssertValid(); var sign = +1; var regNum = new BigIntegerBuilder(dividend, ref sign); var regDen = new BigIntegerBuilder(divisor, ref sign); regNum.Div(ref regDen); return regNum.GetInteger(sign); } public static BigInteger operator %(BigInteger dividend, BigInteger divisor) { dividend.AssertValid(); divisor.AssertValid(); var signNum = +1; var signDen = +1; var regNum = new BigIntegerBuilder(dividend, ref signNum); var regDen = new BigIntegerBuilder(divisor, ref signDen); regNum.Mod(ref regDen); return regNum.GetInteger(signNum); }*/ public static bool operator <(BigInteger left, BigInteger right) { return left.CompareTo(right) < 0; } public static bool operator <=(BigInteger left, BigInteger right) { return left.CompareTo(right) <= 0; } public static bool operator >(BigInteger left, BigInteger right) { return left.CompareTo(right) > 0; } public static bool operator >=(BigInteger left, BigInteger right) { return left.CompareTo(right) >= 0; } public static bool operator ==(BigInteger left, BigInteger right) { return left.Equals(right); } public static bool operator !=(BigInteger left, BigInteger right) { return !left.Equals(right); } /*public static bool operator <(BigInteger left, Int64 right) { return left.CompareTo(right) < 0; } public static bool operator <=(BigInteger left, Int64 right) { return left.CompareTo(right) <= 0; } public static bool operator >(BigInteger left, Int64 right) { return left.CompareTo(right) > 0; } public static bool operator >=(BigInteger left, Int64 right) { return left.CompareTo(right) >= 0; } public static bool operator ==(BigInteger left, Int64 right) { return left.Equals(right); } public static bool operator !=(BigInteger left, Int64 right) { return !left.Equals(right); } public static bool operator <(Int64 left, BigInteger right) { return right.CompareTo(left) > 0; } public static bool operator <=(Int64 left, BigInteger right) { return right.CompareTo(left) >= 0; } public static bool operator >(Int64 left, BigInteger right) { return right.CompareTo(left) < 0; } public static bool operator >=(Int64 left, BigInteger right) { return right.CompareTo(left) <= 0; } public static bool operator ==(Int64 left, BigInteger right) { return right.Equals(left); } public static bool operator !=(Int64 left, BigInteger right) { return !right.Equals(left); } public static bool operator <(BigInteger left, UInt64 right) { return left.CompareTo(right) < 0; } public static bool operator <=(BigInteger left, UInt64 right) { return left.CompareTo(right) <= 0; } public static bool operator >(BigInteger left, UInt64 right) { return left.CompareTo(right) > 0; } public static bool operator >=(BigInteger left, UInt64 right) { return left.CompareTo(right) >= 0; } public static bool operator ==(BigInteger left, UInt64 right) { return left.Equals(right); } public static bool operator !=(BigInteger left, UInt64 right) { return !left.Equals(right); } public static bool operator <(UInt64 left, BigInteger right) { return right.CompareTo(left) > 0; } public static bool operator <=(UInt64 left, BigInteger right) { return right.CompareTo(left) >= 0; } public static bool operator >(UInt64 left, BigInteger right) { return right.CompareTo(left) < 0; } public static bool operator >=(UInt64 left, BigInteger right) { return right.CompareTo(left) <= 0; } public static bool operator ==(UInt64 left, BigInteger right) { return right.Equals(left); } public static bool operator !=(UInt64 left, BigInteger right) { return !right.Equals(left); }*/ #endregion internal static operators // ----- SECTION: private serialization instance methods ---------------- #region private serialization instance methods #endregion private serialization instance methods // ----- SECTION: internal instance utility methods ----------------* #region internal instance utility methods /*private void SetBitsFromDouble(Double value) { int sign, exp; ulong man; bool fFinite; NumericsHelpers.GetDoubleParts(value, out sign, out exp, out man, out fFinite); Contract.Assert(sign == +1 || sign == -1); if (man == 0) { this = Zero; return; } Contract.Assert(man < 1UL << 53); Contract.Assert(exp <= 0 || man >= 1UL << 52); if (exp <= 0) { if (exp <= -kcbitUlong) { this = Zero; return; } this = man >> -exp; if (sign < 0) _sign = -_sign; } else if (exp <= 11) { this = man << exp; if (sign < 0) _sign = -_sign; } else { // Overflow into at least 3 uints. // Move the leading 1 to the high bit. man <<= 11; exp -= 11; // Compute cu and cbit so that exp == 32 * cu - cbit and 0 <= cbit < 32. var cu = (exp - 1) / kcbitUint + 1; var cbit = cu * kcbitUint - exp; Contract.Assert(0 <= cbit && cbit < kcbitUint); Contract.Assert(cu >= 1); // Populate the uints. _bits = new uint[cu + 2]; _bits[cu + 1] = (uint)(man >> (cbit + kcbitUint)); _bits[cu] = (uint)(man >> cbit); if (cbit > 0) _bits[cu - 1] = (uint)man << (kcbitUint - cbit); _sign = sign; } }*/ #endregion internal instance utility methods // ----- SECTION: internal static utility methods ----------------* #region internal static utility methods //[Pure] private static int Length(uint[] rgu) { var cu = rgu.Length; if (rgu[cu - 1] != 0) return cu; Contract.Assert(cu >= 2 && rgu[cu - 2] != 0); return cu - 1; } internal int _Sign { get { return _sign; } } internal uint[] _Bits { get { return _bits; } } /* internal static int BitLengthOfUInt(uint x) { var numBits = 0; while (x > 0) { x >>= 1; numBits++; } return numBits; } */ // // GetPartsForBitManipulation - // // Encapsulate the logic of normalizing the "small" and "large" forms of BigInteger // into the "large" form so that Bit Manipulation algorithms can be simplified // // uint[] xd = the UInt32 array containing the entire big integer in "large" (denormalized) form // E.g., the number one (1) and negative one (-1) are both stored as 0x00000001 // BigInteger values Int32.MinValue < x <= Int32.MaxValue are converted to this // format for convenience. // int xl = the length of xd // return bool = true for negative numbers // /*private static bool GetPartsForBitManipulation(ref BigInteger x, out uint[] xd, out int xl) { if (x._bits == null) { xd = x._sign < 0 ? new[] { (uint)-x._sign } : new[] { (uint)x._sign }; } else { xd = x._bits; } xl = x._bits == null ? 1 : x._bits.Length; return x._sign < 0; }*/ // Gets an upper bound on the product of uHiRes * (2^32)^(cuRes-1) and uHiMul * (2^32)^(cuMul-1). // The result is put int uHiRes and cuRes. /* private static void MulUpper(ref uint uHiRes, ref int cuRes, uint uHiMul, int cuMul) { var uu = (ulong)uHiRes * uHiMul; var uHi = NumericsHelpers.GetHi(uu); if (uHi != 0) { if (NumericsHelpers.GetLo(uu) != 0 && ++uHi == 0) { uHi = 1; cuRes++; } uHiRes = uHi; cuRes += cuMul; } else { uHiRes = NumericsHelpers.GetLo(uu); cuRes += cuMul - 1; } } */ // Gets a lower bound on the product of uHiRes * (2^32)^(cuRes-1) and uHiMul * (2^32)^(cuMul-1). // The result is put int uHiRes and cuRes. /* private static void MulLower(ref uint uHiRes, ref int cuRes, uint uHiMul, int cuMul) { var uu = (ulong)uHiRes * uHiMul; var uHi = NumericsHelpers.GetHi(uu); if (uHi != 0) { uHiRes = uHi; cuRes += cuMul; } else { uHiRes = NumericsHelpers.GetLo(uu); cuRes += cuMul - 1; } } */ private static int GetDiffLength(uint[] rgu1, uint[] rgu2, int cu) { for (var iv = cu; --iv >= 0; ) { if (rgu1[iv] != rgu2[iv]) return iv + 1; } return 0; } #endregion internal static utility methods } }