/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Microsoft Public License. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Microsoft Public License, please send an email to
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if CLR2
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using Microsoft.Contracts;
using Microsoft.Scripting.Utils;
namespace Microsoft.Scripting.Math{
/// <summary>
/// arbitrary precision integers
/// </summary>
[Serializable]
public sealed class BigInteger : IFormattable, IComparable, IConvertible, IEquatable<BigInteger> {
private const int BitsPerDigit = 32;
private const ulong Base = 0x100000000;
// -1 if negative, +1 if positive, 0 if zero.
private readonly short sign;
// Non-null. data[0] is the least significant 32 bits.
private readonly uint[] data;
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly BigInteger Zero = new BigInteger(0, new uint[0]);
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly BigInteger One = new BigInteger(+1, new uint[] { 1 });
private const int bias = 1075;
[CLSCompliant(false)]
public static BigInteger Create(ulong v) {
return new BigInteger(+1, (uint)v, (uint)(v >> BitsPerDigit));
}
[CLSCompliant(false)]
public static BigInteger Create(uint v) {
if (v == 0) return Zero;
else if (v == 1) return One;
else return new BigInteger(+1, v);
}
public static BigInteger Create(long v) {
ulong x;
int s = +1;
if (v < 0) {
x = (ulong)-v; s = -1;
} else {
x = (ulong)v;
}
return new BigInteger(s, (uint)x, (uint)(x >> BitsPerDigit));
}
public static BigInteger Create(int v) {
if (v == 0) return Zero;
else if (v == 1) return One;
else if (v < 0) return new BigInteger(-1, (uint)-v);
else return new BigInteger(+1, (uint)v);
}
private const Int32 DecimalScaleFactorMask = 0x00FF0000;
private const Int32 DecimalSignMask = unchecked((Int32)0x80000000);
public static BigInteger Create(decimal v) {
// First truncate to get scale to 0 and extract bits
int[] bits = Decimal.GetBits(Decimal.Truncate(v));
Debug.Assert(bits.Length == 4 && (bits[3] & DecimalScaleFactorMask) == 0);
int size = 3;
while (size > 0 && bits[size - 1] == 0) size--;
if (size == 0) {
return BigInteger.Zero;
}
UInt32[] array = new UInt32[size];
array[0] = (UInt32)bits[0];
if (size > 1) array[1] = (UInt32)bits[1];
if (size > 2) array[2] = (UInt32)bits[2];
return new BigInteger(((bits[3] & DecimalSignMask) != 0) ? -1 : +1, array);
}
/// <summary>
/// Create a BigInteger from a little-endian twos-complement byte array
/// (inverse of ToByteArray())
/// </summary>
public static BigInteger Create(byte[] v) {
ContractUtils.RequiresNotNull(v, "v");
if (v.Length == 0) return Create(0);
int byteCount = v.Length;
int unalignedBytes = byteCount % 4;
int dwordCount = byteCount / 4 + (unalignedBytes == 0 ? 0 : 1);
uint[] data = new uint[dwordCount];
bool isNegative = (v[byteCount - 1] & 0x80) == 0x80;
bool isZero = true;
// Copy all dwords, except but don't do the last one if it's not a full four bytes
int curDword, curByte, byteInDword;
curByte = 3;
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) {
byteInDword = 0;
while (byteInDword < 4) {
if (v[curByte] != 0x00) isZero = false;
data[curDword] <<= 8;
data[curDword] |= v[curByte];
curByte--;
byteInDword++;
}
curByte += 8;
}
// Copy the last dword specially if it's not aligned
if (unalignedBytes != 0) {
if (isNegative) data[dwordCount - 1] = 0xffffffff;
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) {
if (v[curByte] != 0x00) isZero = false;
data[curDword] <<= 8;
data[curDword] |= v[curByte];
}
}
if (isZero) return Zero;
if (isNegative) {
makeTwosComplement(data);
return new BigInteger(-1, data);
}
return new BigInteger(1, data);
}
private static bool Negative(byte[] v) {
return ((v[7] & 0x80) != 0);
}
private static ushort Exponent(byte[] v) {
return (ushort)((((ushort)(v[7] & 0x7F)) << (ushort)4) | (((ushort)(v[6] & 0xF0)) >> 4));
}
private static ulong Mantissa(byte[] v) {
uint i1 = ((uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24));
uint i2 = ((uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16));
return (ulong)((ulong)i1 | ((ulong)i2 << 32));
}
public static BigInteger Create(double v) {
if (Double.IsNaN(v) || Double.IsInfinity(v)) {
throw new OverflowException();
}
byte[] bytes = System.BitConverter.GetBytes(v);
ulong mantissa = Mantissa(bytes);
if (mantissa == 0) {
// 1.0 * 2**exp, we have a power of 2
int exponent = Exponent(bytes);
if (exponent == 0) return Zero;
BigInteger res = Negative(bytes) ? Negate(One) : One;
res = res << (exponent - 0x3ff);
return res;
} else {
// 1.mantissa * 2**exp
int exponent = Exponent(bytes);
mantissa |= 0x10000000000000ul;
BigInteger res = BigInteger.Create(mantissa);
res = exponent > bias ? res << (exponent - bias) : res >> (bias - exponent);
return Negative(bytes) ? res * (-1) : res;
}
}
public static implicit operator BigInteger(byte i) {
return Create((uint)i);
}
[CLSCompliant(false)]
public static implicit operator BigInteger(sbyte i) {
return Create((int)i);
}
public static implicit operator BigInteger(short i) {
return Create((int)i);
}
[CLSCompliant(false)]
public static implicit operator BigInteger(ushort i) {
return Create((uint)i);
}
[CLSCompliant(false)]
public static implicit operator BigInteger(uint i) {
return Create(i);
}
public static implicit operator BigInteger(int i) {
return Create(i);
}
[CLSCompliant(false)]
public static implicit operator BigInteger(ulong i) {
return Create(i);
}
public static implicit operator BigInteger(long i) {
return Create(i);
}
public static implicit operator BigInteger(decimal i) {
return Create(i);
}
public static explicit operator BigInteger(double self) {
return Create(self);
}
public static explicit operator BigInteger(float self) {
return Create((double)self);
}
public static explicit operator double(BigInteger self) {
if (object.ReferenceEquals(self, null)) {
throw new ArgumentNullException("self");
}
return self.ToFloat64();
}
public static explicit operator float(BigInteger self) {
if (object.ReferenceEquals(self, null)) {
throw new ArgumentNullException("self");
}
return checked((float)self.ToFloat64());
}
public static explicit operator decimal(BigInteger self) {
decimal res;
if (self.AsDecimal(out res)) {
return res;
}
throw new OverflowException();
}
public static explicit operator byte(BigInteger self) {
int tmp;
if (self.AsInt32(out tmp)) {
return checked((byte)tmp);
}
throw new OverflowException();
}
[CLSCompliant(false)]
public static explicit operator sbyte(BigInteger self) {
int tmp;
if (self.AsInt32(out tmp)) {
return checked((sbyte)tmp);
}
throw new OverflowException();
}
[CLSCompliant(false)]
public static explicit operator UInt16(BigInteger self) {
int tmp;
if (self.AsInt32(out tmp)) {
return checked((UInt16)tmp);
}
throw new OverflowException();
}
public static explicit operator Int16(BigInteger self) {
int tmp;
if (self.AsInt32(out tmp)) {
return checked((Int16)tmp);
}
throw new OverflowException();
}
[CLSCompliant(false)]
public static explicit operator UInt32(BigInteger self) {
uint tmp;
if (self.AsUInt32(out tmp)) {
return tmp;
}
throw new OverflowException();
}
public static explicit operator Int32(BigInteger self) {
int tmp;
if (self.AsInt32(out tmp)) {
return tmp;
}
throw new OverflowException();
}
public static explicit operator Int64(BigInteger self) {
long tmp;
if (self.AsInt64(out tmp)) {
return tmp;
}
throw new OverflowException();
}
[CLSCompliant(false)]
public static explicit operator UInt64(BigInteger self) {
ulong tmp;
if (self.AsUInt64(out tmp)) {
return tmp;
}
throw new OverflowException();
}
public BigInteger(BigInteger copy) {
if (object.ReferenceEquals(copy, null)) {
throw new ArgumentNullException("copy");
}
this.sign = copy.sign;
this.data = copy.data;
}
public BigInteger(byte[] bytes) : this(Create(bytes)) { }
[CLSCompliant(false)]
public BigInteger(int sign, params uint[] data) {
ContractUtils.RequiresNotNull(data, "data");
ContractUtils.Requires(sign >= -1 && sign <= +1, "sign");
int length = GetLength(data);
ContractUtils.Requires(length == 0 || sign != 0, "sign");
this.data = data;
this.sign = (short)(length == 0 ? 0 : sign);
}
/// <summary>
/// Return the magnitude of this BigInteger as an array of zero or more uints.
/// Element zero is the value of the least significant four bytes, element one is
/// the value of the four next most significant bytes, etc.
///
/// The returned data is the unsigned magnitude of the number. To determine the sign,
/// use GetSign().
///
/// It is guaranteed that the highest element of the returned array is never zero.
/// This means that if the value of this BigInteger is zero, a zero-length array
/// is returned.
/// </summary>
[CLSCompliant(false)]
public uint[] GetWords() {
if (sign == 0) return new uint[] { 0 };
int w = GetLength();
uint[] bits = new uint[w];
Array.Copy(data, bits, w);
return bits;
}
[CLSCompliant(false)]
public uint GetWord(int index) {
return data[index];
}
public int GetBitCount() {
if (IsZero()) {
return 1;
}
int w = GetLength() - 1;
uint b = data[w];
Debug.Assert(b > 0);
int result = w * 32;
do {
b >>= 1;
result++;
} while (b > 0);
return result;
}
public int GetByteCount() {
return (GetBitCount() + 7) / 8;
}
/// <summary>
/// Return the sign of this BigInteger: -1, 0, or 1.
/// </summary>
public short Sign {
get {
return sign;
}
}
public bool AsInt64(out long ret) {
ret = 0;
if (sign == 0) return true;
if (GetLength() > 2) return false;
if (data.Length == 1) {
ret = sign * (long)data[0];
return true;
}
ulong tmp = (((ulong)data[1]) << 32 | (ulong)data[0]);
if (tmp > 0x8000000000000000) return false;
if (tmp == 0x8000000000000000 && sign == 1) return false;
ret = ((long)tmp) * sign;
return true;
}
[CLSCompliant(false)]
public bool AsUInt32(out uint ret) {
ret = 0;
if (sign == 0) return true;
if (sign < 0) return false;
if (GetLength() > 1) return false;
ret = data[0];
return true;
}
[CLSCompliant(false)]
public bool AsUInt64(out ulong ret) {
ret = 0;
if (sign == 0) return true;
if (sign < 0) return false;
if (GetLength() > 2) return false;
ret = (ulong)data[0];
if (data.Length > 1) {
ret |= ((ulong)data[1]) << 32;
}
return true;
}
public bool AsInt32(out int ret) {
ret = 0;
if (sign == 0) return true;
if (GetLength() > 1) return false;
if (data[0] > 0x80000000) return false;
if (data[0] == 0x80000000 && sign == 1) return false;
ret = (int)data[0];
ret *= sign;
return true;
}
public bool AsDecimal(out Decimal ret) {
if (sign == 0) {
ret = Decimal.Zero;
return true;
}
int length = GetLength();
if (length > 3) {
ret = default(Decimal);
return false;
}
int lo = 0, mi = 0, hi = 0;
if (length > 2) hi = (Int32)data[2];
if (length > 1) mi = (Int32)data[1];
if (length > 0) lo = (Int32)data[0];
ret = new Decimal(lo, mi, hi, sign < 0, 0);
return true;
}
[CLSCompliant(false)]
public uint ToUInt32() {
uint ret;
if (AsUInt32(out ret)) return ret;
throw new OverflowException("big integer won't fit into uint");
}
public int ToInt32() {
int ret;
if (AsInt32(out ret)) return ret;
throw new OverflowException("big integer won't fit into int");
}
public decimal ToDecimal() {
decimal ret;
if (AsDecimal(out ret)) return ret;
throw new OverflowException("big integer won't fit into decimal");
}
[CLSCompliant(false)]
public ulong ToUInt64() {
ulong ret;
if (AsUInt64(out ret)) return ret;
throw new OverflowException("big integer won't fit into ulong");
}
public long ToInt64() {
long ret;
if (AsInt64(out ret)) return ret;
throw new OverflowException("big integer won't fit into long");
}
public bool TryToFloat64(out double result) {
return StringUtils.TryParseDouble(ToString(10),
System.Globalization.NumberStyles.Number,
System.Globalization.CultureInfo.InvariantCulture.NumberFormat,
out result);
}
public double ToFloat64() {
return double.Parse(
ToString(10),
System.Globalization.CultureInfo.InvariantCulture.NumberFormat
);
}
public int GetWordCount() {
if (IsZero()) {
return 1;
}
return GetLength();
}
private int GetLength() {
return GetLength(data);
}
private static int GetLength(uint[] data) {
int ret = data.Length - 1;
while (ret >= 0 && data[ret] == 0) ret--;
return ret + 1;
}
private static uint[] copy(uint[] v) {
uint[] ret = new uint[v.Length];
Array.Copy(v, ret, v.Length);
return ret;
}
private static uint[] resize(uint[] v, int len) {
if (v.Length == len) return v;
uint[] ret = new uint[len];
int n = System.Math.Min(v.Length, len);
for (int i = 0; i < n; i++) {
ret[i] = v[i];
}
return ret;
}
private static uint[] InternalAdd(uint[] x, int xl, uint[] y, int yl) {
Debug.Assert(xl >= yl);
uint[] z = new uint[xl];
int i;
ulong sum = 0;
for (i = 0; i < yl; i++) {
sum = sum + x[i] + y[i];
z[i] = (uint)sum;
sum >>= BitsPerDigit;
}
for (; i < xl && sum != 0; i++) {
sum = sum + x[i];
z[i] = (uint)sum;
sum >>= BitsPerDigit;
}
if (sum != 0) {
z = resize(z, xl + 1);
z[i] = (uint)sum;
} else {
for (; i < xl; i++) {
z[i] = x[i];
}
}
return z;
}
private static uint[] sub(uint[] x, int xl, uint[] y, int yl) {
Debug.Assert(xl >= yl);
uint[] z = new uint[xl];
int i;
bool borrow = false;
for (i = 0; i < yl; i++) {
uint xi = x[i];
uint yi = y[i];
if (borrow) {
if (xi == 0) {
xi = 0xffffffff;
borrow = true;
} else {
xi -= 1;
borrow = false;
}
}
if (yi > xi) borrow = true;
z[i] = xi - yi;
}
if (borrow) {
for (; i < xl; i++) {
uint xi = x[i];
z[i] = xi - 1;
if (xi != 0) { i++; break; }
}
}
for (; i < xl; i++) {
z[i] = x[i];
}
return z; // may have leading zeros
}
private static uint[] add0(uint[] x, int xl, uint[] y, int yl) {
if (xl >= yl) return InternalAdd(x, xl, y, yl);
else return InternalAdd(y, yl, x, xl);
}
public static int Compare(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
if (x.sign == y.sign) {
int xl = x.GetLength();
int yl = y.GetLength();
if (xl == yl) {
for (int i = xl - 1; i >= 0; i--) {
if (x.data[i] == y.data[i]) continue;
return x.data[i] > y.data[i] ? x.sign : -x.sign;
}
return 0;
} else {
return xl > yl ? +x.sign : -x.sign;
}
} else {
return x.sign > y.sign ? +1 : -1;
}
}
public static bool operator ==(BigInteger x, int y) {
return x == (BigInteger)y;
}
public static bool operator !=(BigInteger x, int y) {
return !(x == y);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] // TODO: fix
public static bool operator ==(BigInteger x, double y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
// we can hold all double values, but not all double values
// can hold BigInteger values, and we may lose precision. Convert
// the double to a big int, then compare.
if ((y % 1) != 0) return false; // not a whole number, can't be equal
return x == BigInteger.Create(y);
}
public static bool operator ==(double x, BigInteger y) {
return y == x;
}
public static bool operator !=(BigInteger x, double y) {
return !(x == y);
}
public static bool operator !=(double x, BigInteger y) {
return !(x == y);
}
public static bool operator ==(BigInteger x, BigInteger y) {
return Compare(x, y) == 0;
}
public static bool operator !=(BigInteger x, BigInteger y) {
return Compare(x, y) != 0;
}
public static bool operator <(BigInteger x, BigInteger y) {
return Compare(x, y) < 0;
}
public static bool operator <=(BigInteger x, BigInteger y) {
return Compare(x, y) <= 0;
}
public static bool operator >(BigInteger x, BigInteger y) {
return Compare(x, y) > 0;
}
public static bool operator >=(BigInteger x, BigInteger y) {
return Compare(x, y) >= 0;
}
public static BigInteger Add(BigInteger x, BigInteger y) {
return x + y;
}
public static BigInteger operator +(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
if (x.sign == y.sign) {
return new BigInteger(x.sign, add0(x.data, x.GetLength(), y.data, y.GetLength()));
} else {
return x - new BigInteger(-y.sign, y.data); //??? performance issue
}
}
public static BigInteger Subtract(BigInteger x, BigInteger y) {
return x - y;
}
public static BigInteger operator -(BigInteger x, BigInteger y) {
int c = Compare(x, y);
if (c == 0) return Zero;
if (x.sign == y.sign) {
uint[] z;
switch (c * x.sign) {
case +1:
z = sub(x.data, x.GetLength(), y.data, y.GetLength());
break;
case -1:
z = sub(y.data, y.GetLength(), x.data, x.GetLength());
break;
default:
return Zero;
}
return new BigInteger(c, z);
} else {
uint[] z = add0(x.data, x.GetLength(), y.data, y.GetLength());
return new BigInteger(c, z);
}
}
public static BigInteger Multiply(BigInteger x, BigInteger y) {
return x * y;
}
public static BigInteger operator *(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
int xl = x.GetLength();
int yl = y.GetLength();
int zl = xl + yl;
uint[] xd = x.data, yd = y.data, zd = new uint[zl];
for (int xi = 0; xi < xl; xi++) {
uint xv = xd[xi];
int zi = xi;
ulong carry = 0;
for (int yi = 0; yi < yl; yi++) {
carry = carry + ((ulong)xv) * yd[yi] + zd[zi];
zd[zi++] = (uint)carry;
carry >>= BitsPerDigit;
}
while (carry != 0) {
carry += zd[zi];
zd[zi++] = (uint)carry;
carry >>= BitsPerDigit;
}
}
return new BigInteger(x.sign * y.sign, zd);
}
public static BigInteger Divide(BigInteger x, BigInteger y) {
return x / y;
}
public static BigInteger operator /(BigInteger x, BigInteger y) {
BigInteger dummy;
return DivRem(x, y, out dummy);
}
public static BigInteger Mod(BigInteger x, BigInteger y) {
return x % y;
}
public static BigInteger operator %(BigInteger x, BigInteger y) {
BigInteger ret;
DivRem(x, y, out ret);
return ret;
}
private static int GetNormalizeShift(uint value) {
int shift = 0;
if ((value & 0xFFFF0000) == 0) { value <<= 16; shift += 16; }
if ((value & 0xFF000000) == 0) { value <<= 8; shift += 8; }
if ((value & 0xF0000000) == 0) { value <<= 4; shift += 4; }
if ((value & 0xC0000000) == 0) { value <<= 2; shift += 2; }
if ((value & 0x80000000) == 0) { value <<= 1; shift += 1; }
return shift;
}
[Conditional("DEBUG")]
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Scripting.Math.BigInteger")]
private static void TestNormalize(uint[] u, uint[] un, int shift) {
BigInteger i = new BigInteger(1, u);
BigInteger j = new BigInteger(1, un);
BigInteger k = j >> shift;
Debug.Assert(i == k);
}
[Conditional("DEBUG")]
private static void TestDivisionStep(uint[] un, uint[] vn, uint[] q, uint[] u, uint[] v) {
int n = GetLength(v);
int shift = GetNormalizeShift(v[n - 1]);
BigInteger uni = new BigInteger(1, un);
BigInteger vni = new BigInteger(1, vn);
BigInteger qi = new BigInteger(1, q);
BigInteger ui = new BigInteger(1, u);
BigInteger expected = vni * qi + uni;
BigInteger usi = ui << shift;
Debug.Assert(expected == usi);
}
[Conditional("DEBUG")]
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Scripting.Math.BigInteger")]
private static void TestResult(uint[] u, uint[] v, uint[] q, uint[] r) {
BigInteger ui = new BigInteger(1, u);
BigInteger vi = new BigInteger(1, v);
BigInteger qi = new BigInteger(1, q);
BigInteger ri = new BigInteger(1, r);
BigInteger viqi = vi * qi;
BigInteger expected = viqi + ri;
Debug.Assert(ui == expected);
Debug.Assert(ri < vi);
}
private static void Normalize(uint[] u, int l, uint[] un, int shift) {
Debug.Assert(un.Length == l || un.Length == l + 1);
Debug.Assert(un.Length == l + 1 || ((u[l - 1] << shift) >> shift) == u[l - 1]);
Debug.Assert(0 <= shift && shift < 32);
uint carry = 0;
int i;
if (shift > 0) {
int rshift = BitsPerDigit - shift;
for (i = 0; i < l; i++) {
uint ui = u[i];
un[i] = (ui << shift) | carry;
carry = ui >> rshift;
}
} else {
for (i = 0; i < l; i++) {
un[i] = u[i];
}
}
while (i < un.Length) {
un[i++] = 0;
}
if (carry != 0) {
Debug.Assert(l == un.Length - 1);
un[l] = carry;
}
TestNormalize(u, un, shift);
}
private static void Unnormalize(uint[] un, out uint[] r, int shift) {
Debug.Assert(0 <= shift && shift < 32);
int length = GetLength(un);
r = new uint[length];
if (shift > 0) {
int lshift = 32 - shift;
uint carry = 0;
for (int i = length - 1; i >= 0; i--) {
uint uni = un[i];
r[i] = (uni >> shift) | carry;
carry = (uni << lshift);
}
} else {
for (int i = 0; i < length; i++) {
r[i] = un[i];
}
}
TestNormalize(r, un, shift);
}
private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] r) {
int m = GetLength(u);
int n = GetLength(v);
if (n <= 1) {
if (n == 0) {
throw new DivideByZeroException();
}
// Divide by single digit
//
ulong rem = 0;
uint v0 = v[0];
q = new uint[m];
r = new uint[1];
for (int j = m - 1; j >= 0; j--) {
rem *= Base;
rem += u[j];
ulong div = rem / v0;
rem -= div * v0;
q[j] = (uint)div;
}
r[0] = (uint)rem;
} else if (m >= n) {
int shift = GetNormalizeShift(v[n - 1]);
uint[] un = new uint[m + 1];
uint[] vn = new uint[n];
Normalize(u, m, un, shift);
Normalize(v, n, vn, shift);
q = new uint[m - n + 1];
r = null;
TestDivisionStep(un, vn, q, u, v);
// Main division loop
//
for (int j = m - n; j >= 0; j--) {
ulong rr, qq;
int i;
rr = Base * un[j + n] + un[j + n - 1];
qq = rr / vn[n - 1];
rr -= qq * vn[n - 1];
Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);
for (; ; ) {
// Estimate too big ?
//
if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2]))) {
qq--;
rr += (ulong)vn[n - 1];
if (rr < Base) continue;
}
break;
}
Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);
// Multiply and subtract
//
long b = 0;
long t = 0;
for (i = 0; i < n; i++) {
ulong p = vn[i] * qq;
t = (long)un[i + j] - (long)(uint)p - b;
un[i + j] = (uint)t;
p >>= 32;
t >>= 32;
Debug.Assert(t == 0 || t == -1 || t == -2);
b = (long)p - t;
}
t = (long)un[j + n] - b;
un[j + n] = (uint)t;
// Store the calculated value
//
q[j] = (uint)qq;
// Add back vn[0..n] to un[j..j+n]
//
if (t < 0) {
q[j]--;
ulong c = 0;
for (i = 0; i < n; i++) {
c = (ulong)vn[i] + un[j + i] + c;
un[j + i] = (uint)c;
c >>= 32;
}
c += (ulong)un[j + n];
un[j + n] = (uint)c;
}
TestDivisionStep(un, vn, q, u, v);
}
Unnormalize(un, out r, shift);
// Test normalized value ... Call TestNormalize
// only pass the values in different order.
//
TestNormalize(r, un, shift);
} else {
q = new uint[] { 0 };
r = u;
}
TestResult(u, v, q, r);
}
public static BigInteger DivRem(BigInteger x, BigInteger y, out BigInteger remainder) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
uint[] q;
uint[] r;
DivModUnsigned(x.data, y.data, out q, out r);
remainder = new BigInteger(x.sign, r);
return new BigInteger(x.sign * y.sign, q);
}
private static uint extend(uint v, ref bool seenNonZero) {
if (seenNonZero) {
return ~v;
} else {
if (v == 0) {
return 0;
} else {
seenNonZero = true;
return ~v + 1;
}
}
}
private static uint getOne(bool isNeg, uint[] data, int i, ref bool seenNonZero) {
if (i < data.Length) {
uint ret = data[i];
return isNeg ? extend(ret, ref seenNonZero) : ret;
} else {
return isNeg ? uint.MaxValue : 0;
}
}
/// <summary>
/// Do an in-place twos complement of d and also return the result.
/// </summary>
private static uint[] makeTwosComplement(uint[] d) {
// first do complement and +1 as long as carry is needed
int i = 0;
uint v = 0;
for (; i < d.Length; i++) {
v = ~d[i] + 1;
d[i] = v;
if (v != 0) { i++; break; }
}
if (v != 0) {
// now ones complement is sufficient
for (; i < d.Length; i++) {
d[i] = ~d[i];
}
} else {
//??? this is weird
d = resize(d, d.Length + 1);
d[d.Length - 1] = 1;
}
return d;
}
public static BigInteger BitwiseAnd(BigInteger x, BigInteger y) {
return x & y;
}
public static BigInteger operator &(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
int xl = x.GetLength(), yl = y.GetLength();
uint[] xd = x.data, yd = y.data;
int zl = System.Math.Max(xl, yl);
uint[] zd = new uint[zl];
bool negx = x.sign == -1, negy = y.sign == -1;
bool seenNonZeroX = false, seenNonZeroY = false;
for (int i = 0; i < zl; i++) {
uint xu = getOne(negx, xd, i, ref seenNonZeroX);
uint yu = getOne(negy, yd, i, ref seenNonZeroY);
zd[i] = xu & yu;
}
if (negx && negy) {
return new BigInteger(-1, makeTwosComplement(zd));
} else if (negx || negy) {
return new BigInteger(+1, zd);
} else {
return new BigInteger(+1, zd);
}
}
public static BigInteger BitwiseOr(BigInteger x, BigInteger y) {
return x | y;
}
public static BigInteger operator |(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
int xl = x.GetLength(), yl = y.GetLength();
uint[] xd = x.data, yd = y.data;
int zl = System.Math.Max(xl, yl);
uint[] zd = new uint[zl];
bool negx = x.sign == -1, negy = y.sign == -1;
bool seenNonZeroX = false, seenNonZeroY = false;
for (int i = 0; i < zl; i++) {
uint xu = getOne(negx, xd, i, ref seenNonZeroX);
uint yu = getOne(negy, yd, i, ref seenNonZeroY);
zd[i] = xu | yu;
}
if (negx && negy) {
return new BigInteger(-1, makeTwosComplement(zd));
} else if (negx || negy) {
return new BigInteger(-1, makeTwosComplement(zd));
} else {
return new BigInteger(+1, zd);
}
}
public static BigInteger Xor(BigInteger x, BigInteger y) {
return x ^ y;
}
public static BigInteger operator ^(BigInteger x, BigInteger y) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (object.ReferenceEquals(y, null)) {
throw new ArgumentNullException("y");
}
int xl = x.GetLength(), yl = y.GetLength();
uint[] xd = x.data, yd = y.data;
int zl = System.Math.Max(xl, yl);
uint[] zd = new uint[zl];
bool negx = x.sign == -1, negy = y.sign == -1;
bool seenNonZeroX = false, seenNonZeroY = false;
for (int i = 0; i < zl; i++) {
uint xu = getOne(negx, xd, i, ref seenNonZeroX);
uint yu = getOne(negy, yd, i, ref seenNonZeroY);
zd[i] = xu ^ yu;
}
if (negx && negy) {
return new BigInteger(+1, zd);
} else if (negx || negy) {
return new BigInteger(-1, makeTwosComplement(zd));
} else {
return new BigInteger(+1, zd);
}
}
public static BigInteger LeftShift(BigInteger x, int shift) {
return x << shift;
}
public static BigInteger operator <<(BigInteger x, int shift) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (shift == 0) return x;
else if (shift < 0) return x >> -shift;
int digitShift = shift / BitsPerDigit;
int smallShift = shift - (digitShift * BitsPerDigit);
int xl = x.GetLength();
uint[] xd = x.data;
int zl = xl + digitShift + 1;
uint[] zd = new uint[zl];
if (smallShift == 0) {
for (int i = 0; i < xl; i++) {
zd[i + digitShift] = xd[i];
}
} else {
int carryShift = BitsPerDigit - smallShift;
uint carry = 0;
int i;
for (i = 0; i < xl; i++) {
uint rot = xd[i];
zd[i + digitShift] = rot << smallShift | carry;
carry = rot >> carryShift;
}
zd[i + digitShift] = carry;
}
return new BigInteger(x.sign, zd);
}
public static BigInteger RightShift(BigInteger x, int shift) {
return x >> shift;
}
public static BigInteger operator >>(BigInteger x, int shift) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
if (shift == 0) return x;
else if (shift < 0) return x << -shift;
int digitShift = shift / BitsPerDigit;
int smallShift = shift - (digitShift * BitsPerDigit);
int xl = x.GetLength();
uint[] xd = x.data;
int zl = xl - digitShift;
if (zl < 0) zl = 0;
uint[] zd = new uint[zl];
if (smallShift == 0) {
for (int i = xl - 1; i >= digitShift; i--) {
zd[i - digitShift] = xd[i];
}
} else {
int carryShift = BitsPerDigit - smallShift;
uint carry = 0;
for (int i = xl - 1; i >= digitShift; i--) {
uint rot = xd[i];
zd[i - digitShift] = rot >> smallShift | carry;
carry = rot << carryShift;
}
}
BigInteger res = new BigInteger(x.sign, zd);
// We wish to always round down, but shifting our data array (which is not
// stored in 2's-complement form) has caused us to round towards zero instead.
// Correct that here.
if (x.IsNegative()) {
for (int i = 0; i < digitShift; i++) {
if (xd[i] != 0u) {
return res - One;
}
}
if (smallShift > 0 && xd[digitShift] << (BitsPerDigit - smallShift) != 0u) {
return res - One;
}
}
return res;
}
public static BigInteger Negate(BigInteger x) {
return -x;
}
public static BigInteger operator -(BigInteger x) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
return new BigInteger(-x.sign, x.data);
}
public BigInteger OnesComplement() {
return ~this;
}
public static BigInteger operator ~(BigInteger x) {
if (object.ReferenceEquals(x, null)) {
throw new ArgumentNullException("x");
}
return -(x + One);
}
public BigInteger Abs() {
if (this.sign == -1) return -this;
else return this;
}
public BigInteger Power(int exp) {
if (exp == 0) return One;
if (exp < 0) {
throw new ArgumentOutOfRangeException("exp", "exp must be >= 0");
}
BigInteger factor = this;
BigInteger result = One;
while (exp != 0) {
if ((exp & 1) != 0) result = result * factor;
if (exp == 1) break; // avoid costly factor.square()
factor = factor.Square();
exp >>= 1;
}
return result;
}
public BigInteger ModPow(int power, BigInteger mod) {
if (object.ReferenceEquals(mod, null)) {
throw new ArgumentNullException("mod");
}
if (power < 0) {
throw new ArgumentOutOfRangeException("power", "power must be >= 0");
}
BigInteger factor = this;
BigInteger result = One % mod; // Handle special case of power=0, mod=1
while (power != 0) {
if ((power & 1) != 0) {
result = result * factor;
result = result % mod;
}
if (power == 1) break; // avoid costly factor.Square()
factor = factor.Square();
factor = factor % mod;
power >>= 1;
}
return result;
}
public BigInteger ModPow(BigInteger power, BigInteger mod) {
if (object.ReferenceEquals(power, null)) {
throw new ArgumentNullException("power");
}
if (object.ReferenceEquals(mod, null)) {
throw new ArgumentNullException("mod");
}
if (power < 0) {
throw new ArgumentOutOfRangeException("power", "power must be >= 0");
}
BigInteger factor = this;
BigInteger result = One % mod;
while (power != Zero) {
if (power.IsOdd()) {
result = result * factor;
result = result % mod;
}
if (power == One) break; // avoid costly factor.Square()
factor = factor.Square();
factor = factor % mod;
power >>= 1;
}
return result;
}
public BigInteger Square() {
return this * this;
}
[Confined]
public override string ToString() {
return ToString(10);
}
[Confined]
public string ToString(int radix) {
return MathUtils.BigIntegerToString(copy(data), sign, radix);
}
[Confined]
public override int GetHashCode() {
// The Object.GetHashCode function needs to be consistent with the Object.Equals function.
// Languages that build on top of this may have a more flexible equality function and
// so may not be able to use this hash function directly.
// For example, Python allows BigInteger(10) == int32(10), so hashing a BigInt over the Int32
// domain should return the same value as a hash of the Int32.
// If this is in the int32 range, this hash function returns the integer.
if (data.Length == 0) {
return 0;
}
// Add up all uints. We want to incorporate all bits to get good hash distribution.
uint total = 0;
foreach (uint x in data) {
total = unchecked(total + x);
}
int hash = unchecked((int)total);
// The sign is not part of the data array, so explicitly incorporate that.
// This is also needed to ensure that hash(-x) == -x for int32.
if (IsNegative()) {
return unchecked(-hash);
} else {
return hash;
}
}
[Confined]
public override bool Equals(object obj) {
return Equals(obj as BigInteger);
}
[StateIndependent]
public bool Equals(BigInteger other) {
if (object.ReferenceEquals(other, null)) return false;
return this == other;
}
public bool IsNegative() {
return sign < 0;
}
public bool IsZero() {
return sign == 0;
}
public bool IsPositive() {
return sign > 0;
}
private bool IsOdd() {
// must have the lowest-order bit set to 1
return (data != null && data.Length > 0 && ((data[0] & 1) != 0));
}
public double Log(Double newBase) {
if (IsNegative() || newBase == 1.0D || this == Zero || (newBase == 0.0D && this != One)) {
return Double.NaN;
} else if (newBase == Double.PositiveInfinity) {
return this == One ? 0.0D : Double.NaN;
}
int length = GetLength() - 1;
int bitCount = -1;
for (int curBit = 31; curBit >= 0; curBit--) {
if ((data[length] & (1 << curBit)) != 0) {
bitCount = curBit + length * 32;
break;
}
}
long bitlen = bitCount;
Double c = 0, d = 1;
BigInteger testBit = BigInteger.One;
long tempBitlen = bitlen;
while (tempBitlen > Int32.MaxValue) {
testBit = testBit << Int32.MaxValue;
tempBitlen -= Int32.MaxValue;
}
testBit = testBit << (int)tempBitlen;
for (long curbit = bitlen; curbit >= 0; --curbit) {
if ((this & testBit) != BigInteger.Zero)
c += d;
d *= 0.5;
testBit = testBit >> 1;
}
return (System.Math.Log(c) + System.Math.Log(2) * bitlen) / System.Math.Log(newBase);
}
/// <summary>
/// Calculates the natural logarithm of the BigInteger.
/// </summary>
public double Log() {
return Log(System.Math.E);
}
/// <summary>
/// Calculates log base 10 of a BigInteger.
/// </summary>
public double Log10() {
return Log(10);
}
#region IComparable Members
public int CompareTo(object obj) {
if (obj == null) {
return 1;
}
BigInteger o = obj as BigInteger;
if (object.ReferenceEquals(o, null)) {
throw new ArgumentException("expected integer");
}
return Compare(this, o);
}
#endregion
#region IConvertible Members
[Confined]
public TypeCode GetTypeCode() {
return TypeCode.Object;
}
[Confined]
public bool ToBoolean(IFormatProvider provider) {
return this != Zero;
}
[Confined]
public byte ToByte(IFormatProvider provider) {
uint ret;
if (AsUInt32(out ret) && (ret & ~0xFF) == 0) {
return (byte)ret;
}
throw new OverflowException("big integer won't fit into byte");
}
/// <summary>
/// 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.
/// </summary>
public byte[] ToByteArray() {
// 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 a another pass to remove unneeded bytes at the top of the array.
if (0 == sign) return new byte[] { 0 };
uint[] dwords;
byte highByte;
if (-1 == sign) {
dwords = (uint[])this.data.Clone();
makeTwosComplement(dwords);
highByte = 0xff;
} else {
dwords = this.data;
highByte = 0x00;
}
byte[] bytes = new byte[4 * dwords.Length];
int curByte = 0;
uint dword;
for (int i = 0; i < dwords.Length; i++) {
dword = dwords[i];
for (int j = 0; j < 4; j++) {
bytes[curByte++] = (byte)(dword & 0xff);
dword >>= 8;
}
}
// find highest significant byte
int msb;
for (msb = bytes.Length - 1; msb > 0; msb--) {
if (bytes[msb] != highByte) break;
}
// ensure high bit is 0 if positive, 1 if negative
bool needExtraByte = (bytes[msb] & 0x80) != (highByte & 0x80);
byte[] trimmedBytes = new byte[msb + 1 + (needExtraByte ? 1 : 0)];
Array.Copy(bytes, trimmedBytes, msb + 1);
if (needExtraByte) trimmedBytes[trimmedBytes.Length - 1] = highByte;
return trimmedBytes;
}
[Confined]
public char ToChar(IFormatProvider provider) {
int ret;
if (AsInt32(out ret) && (ret <= Char.MaxValue) && (ret >= Char.MinValue)) {
return (char)ret;
}
throw new OverflowException("big integer won't fit into char");
}
[Confined]
public DateTime ToDateTime(IFormatProvider provider) {
throw new NotImplementedException();
}
[Confined]
public decimal ToDecimal(IFormatProvider provider) {
decimal ret;
if (AsDecimal(out ret)) return ret;
throw new OverflowException("big integer won't fit into decimal");
}
[Confined]
public double ToDouble(IFormatProvider provider) {
return this.ToFloat64();
}
[Confined]
public short ToInt16(IFormatProvider provider) {
int ret;
if (AsInt32(out ret) && (ret <= short.MaxValue) && (ret >= short.MinValue)) {
return (short)ret;
}
throw new OverflowException("big integer won't fit into short");
}
[Confined]
public int ToInt32(IFormatProvider provider) {
int ret;
if (AsInt32(out ret)) {
return ret;
}
throw new OverflowException("big integer won't fit into int");
}
[Confined]
public long ToInt64(IFormatProvider provider) {
long ret;
if (AsInt64(out ret)) {
return ret;
}
throw new OverflowException("big integer won't fit into long");
}
[CLSCompliant(false), Confined]
public sbyte ToSByte(IFormatProvider provider) {
int ret;
if (AsInt32(out ret) && (ret <= sbyte.MaxValue) && (ret >= sbyte.MinValue)) {
return (sbyte)ret;
}
throw new OverflowException("big integer won't fit into sbyte");
}
[Confined]
public float ToSingle(IFormatProvider provider) {
return checked((float)ToDouble(provider));
}
[Confined]
public string ToString(IFormatProvider provider) {
return ToString();
}
[Confined]
public object ToType(Type conversionType, IFormatProvider provider) {
if (conversionType == typeof(BigInteger)) {
return this;
}
throw new NotImplementedException();
}
[CLSCompliant(false), Confined]
public ushort ToUInt16(IFormatProvider provider) {
uint ret;
if (AsUInt32(out ret) && ret <= ushort.MaxValue) {
return (ushort)ret;
}
throw new OverflowException("big integer won't fit into ushort");
}
[CLSCompliant(false), Confined]
public uint ToUInt32(IFormatProvider provider) {
uint ret;
if (AsUInt32(out ret)) {
return ret;
}
throw new OverflowException("big integer won't fit into uint");
}
[CLSCompliant(false), Confined]
public ulong ToUInt64(IFormatProvider provider) {
ulong ret;
if (AsUInt64(out ret)) {
return ret;
}
throw new OverflowException("big integer won't fit into ulong");
}
#endregion
#region IFormattable Members
string IFormattable.ToString(string format, IFormatProvider formatProvider) {
if (format == null) return this.ToString();
switch (format[0]) {
case 'd':
case 'D':
if (format.Length > 1) {
int precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat);
string baseStr = ToString(10);
if (baseStr.Length < precision) {
string additional = new String('0', precision - baseStr.Length);
if (baseStr[0] != '-') {
return additional + baseStr;
} else {
return "-" + additional + baseStr.Substring(1);
}
}
return baseStr;
}
return ToString(10);
case 'x':
case 'X':
StringBuilder res = new StringBuilder(ToString(16));
if (format[0] == 'x') {
for (int i = 0; i < res.Length; i++) {
if (res[i] >= 'A' && res[i] <= 'F') {
res[i] = Char.ToLower(res[i], CultureInfo.InvariantCulture);
}
}
}
if (format.Length > 1) {
int precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat);
if (res.Length < precision) {
string additional = new String('0', precision - res.Length);
if (res[0] != '-') {
res.Insert(0, additional);
} else {
res.Insert(1, additional);
}
}
}
return res.ToString();
default:
throw new NotImplementedException("format not implemented");
}
}
#endregion
}
}
#endif
|