2012 lines
49 KiB
C#
2012 lines
49 KiB
C#
// ==++==
|
|
//
|
|
// 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<BigInteger>, IEquatable<BigInteger>*/
|
|
{
|
|
// ---- 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
|
|
}
|
|
} |