|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.math; |
|
|
|
/** |
|
* A class used to represent multiprecision integers that makes efficient |
|
* use of allocated space by allowing a number to occupy only part of |
|
* an array so that the arrays do not have to be reallocated as often. |
|
* When performing an operation with many iterations the array used to |
|
* hold a number is only reallocated when necessary and does not have to |
|
* be the same size as the number it represents. A mutable number allows |
|
* calculations to occur on the same number without having to create |
|
* a new number for every step of the calculation as occurs with |
|
* BigIntegers. |
|
* |
|
* @see BigInteger |
|
* @author Michael McCloskey |
|
* @author Timothy Buktu |
|
* @since 1.3 |
|
*/ |
|
|
|
import static java.math.BigDecimal.INFLATED; |
|
import static java.math.BigInteger.LONG_MASK; |
|
import java.util.Arrays; |
|
|
|
class MutableBigInteger { |
|
|
|
|
|
|
|
|
|
*/ |
|
int[] value; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
int intLen; |
|
|
|
|
|
|
|
|
|
*/ |
|
int offset = 0; |
|
|
|
// Constants |
|
|
|
|
|
|
|
|
|
*/ |
|
static final MutableBigInteger ONE = new MutableBigInteger(1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static final int KNUTH_POW2_THRESH_LEN = 6; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static final int KNUTH_POW2_THRESH_ZEROS = 3; |
|
|
|
// Constructors |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger() { |
|
value = new int[1]; |
|
intLen = 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger(int val) { |
|
value = new int[1]; |
|
intLen = 1; |
|
value[0] = val; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger(int[] val) { |
|
value = val; |
|
intLen = val.length; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger(BigInteger b) { |
|
intLen = b.mag.length; |
|
value = Arrays.copyOf(b.mag, intLen); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger(MutableBigInteger val) { |
|
intLen = val.intLen; |
|
value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void ones(int n) { |
|
if (n > value.length) |
|
value = new int[n]; |
|
Arrays.fill(value, -1); |
|
offset = 0; |
|
intLen = n; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int[] getMagnitudeArray() { |
|
if (offset > 0 || value.length != intLen) |
|
return Arrays.copyOfRange(value, offset, offset + intLen); |
|
return value; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private long toLong() { |
|
assert (intLen <= 2) : "this MutableBigInteger exceeds the range of long"; |
|
if (intLen == 0) |
|
return 0; |
|
long d = value[offset] & LONG_MASK; |
|
return (intLen == 2) ? d << 32 | (value[offset + 1] & LONG_MASK) : d; |
|
} |
|
|
|
|
|
|
|
*/ |
|
BigInteger toBigInteger(int sign) { |
|
if (intLen == 0 || sign == 0) |
|
return BigInteger.ZERO; |
|
return new BigInteger(getMagnitudeArray(), sign); |
|
} |
|
|
|
|
|
|
|
*/ |
|
BigInteger toBigInteger() { |
|
normalize(); |
|
return toBigInteger(isZero() ? 0 : 1); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
BigDecimal toBigDecimal(int sign, int scale) { |
|
if (intLen == 0 || sign == 0) |
|
return BigDecimal.zeroValueOf(scale); |
|
int[] mag = getMagnitudeArray(); |
|
int len = mag.length; |
|
int d = mag[0]; |
|
// If this MutableBigInteger can't be fit into long, we need to |
|
|
|
if (len > 2 || (d < 0 && len == 2)) |
|
return new BigDecimal(new BigInteger(mag, sign), INFLATED, scale, 0); |
|
long v = (len == 2) ? |
|
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : |
|
d & LONG_MASK; |
|
return BigDecimal.valueOf(sign == -1 ? -v : v, scale); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
long toCompactValue(int sign) { |
|
if (intLen == 0 || sign == 0) |
|
return 0L; |
|
int[] mag = getMagnitudeArray(); |
|
int len = mag.length; |
|
int d = mag[0]; |
|
// If this MutableBigInteger can not be fitted into long, we need to |
|
|
|
if (len > 2 || (d < 0 && len == 2)) |
|
return INFLATED; |
|
long v = (len == 2) ? |
|
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : |
|
d & LONG_MASK; |
|
return sign == -1 ? -v : v; |
|
} |
|
|
|
|
|
|
|
*/ |
|
void clear() { |
|
offset = intLen = 0; |
|
for (int index=0, n=value.length; index < n; index++) |
|
value[index] = 0; |
|
} |
|
|
|
|
|
|
|
*/ |
|
void reset() { |
|
offset = intLen = 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final int compare(MutableBigInteger b) { |
|
int blen = b.intLen; |
|
if (intLen < blen) |
|
return -1; |
|
if (intLen > blen) |
|
return 1; |
|
|
|
// Add Integer.MIN_VALUE to make the comparison act as unsigned integer |
|
|
|
int[] bval = b.value; |
|
for (int i = offset, j = b.offset; i < intLen + offset; i++, j++) { |
|
int b1 = value[i] + 0x80000000; |
|
int b2 = bval[j] + 0x80000000; |
|
if (b1 < b2) |
|
return -1; |
|
if (b1 > b2) |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int compareShifted(MutableBigInteger b, int ints) { |
|
int blen = b.intLen; |
|
int alen = intLen - ints; |
|
if (alen < blen) |
|
return -1; |
|
if (alen > blen) |
|
return 1; |
|
|
|
// Add Integer.MIN_VALUE to make the comparison act as unsigned integer |
|
|
|
int[] bval = b.value; |
|
for (int i = offset, j = b.offset; i < alen + offset; i++, j++) { |
|
int b1 = value[i] + 0x80000000; |
|
int b2 = bval[j] + 0x80000000; |
|
if (b1 < b2) |
|
return -1; |
|
if (b1 > b2) |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final int compareHalf(MutableBigInteger b) { |
|
int blen = b.intLen; |
|
int len = intLen; |
|
if (len <= 0) |
|
return blen <= 0 ? 0 : -1; |
|
if (len > blen) |
|
return 1; |
|
if (len < blen - 1) |
|
return -1; |
|
int[] bval = b.value; |
|
int bstart = 0; |
|
int carry = 0; |
|
|
|
if (len != blen) { |
|
if (bval[bstart] == 1) { |
|
++bstart; |
|
carry = 0x80000000; |
|
} else |
|
return -1; |
|
} |
|
// compare values with right-shifted values of b, |
|
|
|
int[] val = value; |
|
for (int i = offset, j = bstart; i < len + offset;) { |
|
int bv = bval[j++]; |
|
long hb = ((bv >>> 1) + carry) & LONG_MASK; |
|
long v = val[i++] & LONG_MASK; |
|
if (v != hb) |
|
return v < hb ? -1 : 1; |
|
carry = (bv & 1) << 31; |
|
} |
|
return carry == 0 ? 0 : -1; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private final int getLowestSetBit() { |
|
if (intLen == 0) |
|
return -1; |
|
int j, b; |
|
for (j=intLen-1; (j > 0) && (value[j+offset] == 0); j--) |
|
; |
|
b = value[j+offset]; |
|
if (b == 0) |
|
return -1; |
|
return ((intLen-1-j)<<5) + Integer.numberOfTrailingZeros(b); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final int getInt(int index) { |
|
return value[offset+index]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final long getLong(int index) { |
|
return value[offset+index] & LONG_MASK; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final void normalize() { |
|
if (intLen == 0) { |
|
offset = 0; |
|
return; |
|
} |
|
|
|
int index = offset; |
|
if (value[index] != 0) |
|
return; |
|
|
|
int indexBound = index+intLen; |
|
do { |
|
index++; |
|
} while(index < indexBound && value[index] == 0); |
|
|
|
int numZeros = index - offset; |
|
intLen -= numZeros; |
|
offset = (intLen == 0 ? 0 : offset+numZeros); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private final void ensureCapacity(int len) { |
|
if (value.length < len) { |
|
value = new int[len]; |
|
offset = 0; |
|
intLen = len; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
int[] toIntArray() { |
|
int[] result = new int[intLen]; |
|
for(int i=0; i < intLen; i++) |
|
result[i] = value[offset+i]; |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void setInt(int index, int val) { |
|
value[offset + index] = val; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void setValue(int[] val, int length) { |
|
value = val; |
|
intLen = length; |
|
offset = 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void copyValue(MutableBigInteger src) { |
|
int len = src.intLen; |
|
if (value.length < len) |
|
value = new int[len]; |
|
System.arraycopy(src.value, src.offset, value, 0, len); |
|
intLen = len; |
|
offset = 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void copyValue(int[] val) { |
|
int len = val.length; |
|
if (value.length < len) |
|
value = new int[len]; |
|
System.arraycopy(val, 0, value, 0, len); |
|
intLen = len; |
|
offset = 0; |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isOne() { |
|
return (intLen == 1) && (value[offset] == 1); |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isZero() { |
|
return (intLen == 0); |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isEven() { |
|
return (intLen == 0) || ((value[offset + intLen - 1] & 1) == 0); |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isOdd() { |
|
return isZero() ? false : ((value[offset + intLen - 1] & 1) == 1); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
boolean isNormal() { |
|
if (intLen + offset > value.length) |
|
return false; |
|
if (intLen == 0) |
|
return true; |
|
return (value[offset] != 0); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String toString() { |
|
BigInteger b = toBigInteger(1); |
|
return b.toString(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
void safeRightShift(int n) { |
|
if (n/32 >= intLen) { |
|
reset(); |
|
} else { |
|
rightShift(n); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void rightShift(int n) { |
|
if (intLen == 0) |
|
return; |
|
int nInts = n >>> 5; |
|
int nBits = n & 0x1F; |
|
this.intLen -= nInts; |
|
if (nBits == 0) |
|
return; |
|
int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]); |
|
if (nBits >= bitsInHighWord) { |
|
this.primitiveLeftShift(32 - nBits); |
|
this.intLen--; |
|
} else { |
|
primitiveRightShift(nBits); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
void safeLeftShift(int n) { |
|
if (n > 0) { |
|
leftShift(n); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
void leftShift(int n) { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (intLen == 0) |
|
return; |
|
int nInts = n >>> 5; |
|
int nBits = n&0x1F; |
|
int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]); |
|
|
|
|
|
if (n <= (32-bitsInHighWord)) { |
|
primitiveLeftShift(nBits); |
|
return; |
|
} |
|
|
|
int newLen = intLen + nInts +1; |
|
if (nBits <= (32-bitsInHighWord)) |
|
newLen--; |
|
if (value.length < newLen) { |
|
|
|
int[] result = new int[newLen]; |
|
for (int i=0; i < intLen; i++) |
|
result[i] = value[offset+i]; |
|
setValue(result, newLen); |
|
} else if (value.length - offset >= newLen) { |
|
|
|
for(int i=0; i < newLen - intLen; i++) |
|
value[offset+intLen+i] = 0; |
|
} else { |
|
|
|
for (int i=0; i < intLen; i++) |
|
value[i] = value[offset+i]; |
|
for (int i=intLen; i < newLen; i++) |
|
value[i] = 0; |
|
offset = 0; |
|
} |
|
intLen = newLen; |
|
if (nBits == 0) |
|
return; |
|
if (nBits <= (32-bitsInHighWord)) |
|
primitiveLeftShift(nBits); |
|
else |
|
primitiveRightShift(32 -nBits); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int divadd(int[] a, int[] result, int offset) { |
|
long carry = 0; |
|
|
|
for (int j=a.length-1; j >= 0; j--) { |
|
long sum = (a[j] & LONG_MASK) + |
|
(result[j+offset] & LONG_MASK) + carry; |
|
result[j+offset] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
return (int)carry; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int mulsub(int[] q, int[] a, int x, int len, int offset) { |
|
long xLong = x & LONG_MASK; |
|
long carry = 0; |
|
offset += len; |
|
|
|
for (int j=len-1; j >= 0; j--) { |
|
long product = (a[j] & LONG_MASK) * xLong + carry; |
|
long difference = q[offset] - product; |
|
q[offset--] = (int)difference; |
|
carry = (product >>> 32) |
|
+ (((difference & LONG_MASK) > |
|
(((~(int)product) & LONG_MASK))) ? 1:0); |
|
} |
|
return (int)carry; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset) { |
|
long xLong = x & LONG_MASK; |
|
long carry = 0; |
|
offset += len; |
|
for (int j=len-1; j >= 0; j--) { |
|
long product = (a[j] & LONG_MASK) * xLong + carry; |
|
long difference = q[offset--] - product; |
|
carry = (product >>> 32) |
|
+ (((difference & LONG_MASK) > |
|
(((~(int)product) & LONG_MASK))) ? 1:0); |
|
} |
|
return (int)carry; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final void primitiveRightShift(int n) { |
|
int[] val = value; |
|
int n2 = 32 - n; |
|
for (int i=offset+intLen-1, c=val[i]; i > offset; i--) { |
|
int b = c; |
|
c = val[i-1]; |
|
val[i] = (c << n2) | (b >>> n); |
|
} |
|
val[offset] >>>= n; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final void primitiveLeftShift(int n) { |
|
int[] val = value; |
|
int n2 = 32 - n; |
|
for (int i=offset, c=val[i], m=i+intLen-1; i < m; i++) { |
|
int b = c; |
|
c = val[i+1]; |
|
val[i] = (b << n) | (c >>> n2); |
|
} |
|
val[offset+intLen-1] <<= n; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private BigInteger getLower(int n) { |
|
if (isZero()) { |
|
return BigInteger.ZERO; |
|
} else if (intLen < n) { |
|
return toBigInteger(1); |
|
} else { |
|
|
|
int len = n; |
|
while (len > 0 && value[offset+intLen-len] == 0) |
|
len--; |
|
int sign = len > 0 ? 1 : 0; |
|
return new BigInteger(Arrays.copyOfRange(value, offset+intLen-len, offset+intLen), sign); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void keepLower(int n) { |
|
if (intLen >= n) { |
|
offset += intLen - n; |
|
intLen = n; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void add(MutableBigInteger addend) { |
|
int x = intLen; |
|
int y = addend.intLen; |
|
int resultLen = (intLen > addend.intLen ? intLen : addend.intLen); |
|
int[] result = (value.length < resultLen ? new int[resultLen] : value); |
|
|
|
int rstart = result.length-1; |
|
long sum; |
|
long carry = 0; |
|
|
|
|
|
while(x > 0 && y > 0) { |
|
x--; y--; |
|
sum = (value[x+offset] & LONG_MASK) + |
|
(addend.value[y+addend.offset] & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
|
|
|
|
while(x > 0) { |
|
x--; |
|
if (carry == 0 && result == value && rstart == (x + offset)) |
|
return; |
|
sum = (value[x+offset] & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
while(y > 0) { |
|
y--; |
|
sum = (addend.value[y+addend.offset] & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
|
|
if (carry > 0) { |
|
resultLen++; |
|
if (result.length < resultLen) { |
|
int temp[] = new int[resultLen]; |
|
// Result one word longer from carry-out; copy low-order |
|
|
|
System.arraycopy(result, 0, temp, 1, result.length); |
|
temp[0] = 1; |
|
result = temp; |
|
} else { |
|
result[rstart--] = 1; |
|
} |
|
} |
|
|
|
value = result; |
|
intLen = resultLen; |
|
offset = result.length - resultLen; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void addShifted(MutableBigInteger addend, int n) { |
|
if (addend.isZero()) { |
|
return; |
|
} |
|
|
|
int x = intLen; |
|
int y = addend.intLen + n; |
|
int resultLen = (intLen > y ? intLen : y); |
|
int[] result = (value.length < resultLen ? new int[resultLen] : value); |
|
|
|
int rstart = result.length-1; |
|
long sum; |
|
long carry = 0; |
|
|
|
|
|
while (x > 0 && y > 0) { |
|
x--; y--; |
|
int bval = y+addend.offset < addend.value.length ? addend.value[y+addend.offset] : 0; |
|
sum = (value[x+offset] & LONG_MASK) + |
|
(bval & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
|
|
|
|
while (x > 0) { |
|
x--; |
|
if (carry == 0 && result == value && rstart == (x + offset)) { |
|
return; |
|
} |
|
sum = (value[x+offset] & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
while (y > 0) { |
|
y--; |
|
int bval = y+addend.offset < addend.value.length ? addend.value[y+addend.offset] : 0; |
|
sum = (bval & LONG_MASK) + carry; |
|
result[rstart--] = (int)sum; |
|
carry = sum >>> 32; |
|
} |
|
|
|
if (carry > 0) { |
|
resultLen++; |
|
if (result.length < resultLen) { |
|
int temp[] = new int[resultLen]; |
|
// Result one word longer from carry-out; copy low-order |
|
|
|
System.arraycopy(result, 0, temp, 1, result.length); |
|
temp[0] = 1; |
|
result = temp; |
|
} else { |
|
result[rstart--] = 1; |
|
} |
|
} |
|
|
|
value = result; |
|
intLen = resultLen; |
|
offset = result.length - resultLen; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void addDisjoint(MutableBigInteger addend, int n) { |
|
if (addend.isZero()) |
|
return; |
|
|
|
int x = intLen; |
|
int y = addend.intLen + n; |
|
int resultLen = (intLen > y ? intLen : y); |
|
int[] result; |
|
if (value.length < resultLen) |
|
result = new int[resultLen]; |
|
else { |
|
result = value; |
|
Arrays.fill(value, offset+intLen, value.length, 0); |
|
} |
|
|
|
int rstart = result.length-1; |
|
|
|
|
|
System.arraycopy(value, offset, result, rstart+1-x, x); |
|
y -= x; |
|
rstart -= x; |
|
|
|
int len = Math.min(y, addend.value.length-addend.offset); |
|
System.arraycopy(addend.value, addend.offset, result, rstart+1-y, len); |
|
|
|
|
|
for (int i=rstart+1-y+len; i < rstart+1; i++) |
|
result[i] = 0; |
|
|
|
value = result; |
|
intLen = resultLen; |
|
offset = result.length - resultLen; |
|
} |
|
|
|
|
|
|
|
*/ |
|
void addLower(MutableBigInteger addend, int n) { |
|
MutableBigInteger a = new MutableBigInteger(addend); |
|
if (a.offset + a.intLen >= n) { |
|
a.offset = a.offset + a.intLen - n; |
|
a.intLen = n; |
|
} |
|
a.normalize(); |
|
add(a); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
int subtract(MutableBigInteger b) { |
|
MutableBigInteger a = this; |
|
|
|
int[] result = value; |
|
int sign = a.compare(b); |
|
|
|
if (sign == 0) { |
|
reset(); |
|
return 0; |
|
} |
|
if (sign < 0) { |
|
MutableBigInteger tmp = a; |
|
a = b; |
|
b = tmp; |
|
} |
|
|
|
int resultLen = a.intLen; |
|
if (result.length < resultLen) |
|
result = new int[resultLen]; |
|
|
|
long diff = 0; |
|
int x = a.intLen; |
|
int y = b.intLen; |
|
int rstart = result.length - 1; |
|
|
|
|
|
while (y > 0) { |
|
x--; y--; |
|
|
|
diff = (a.value[x+a.offset] & LONG_MASK) - |
|
(b.value[y+b.offset] & LONG_MASK) - ((int)-(diff>>32)); |
|
result[rstart--] = (int)diff; |
|
} |
|
|
|
while (x > 0) { |
|
x--; |
|
diff = (a.value[x+a.offset] & LONG_MASK) - ((int)-(diff>>32)); |
|
result[rstart--] = (int)diff; |
|
} |
|
|
|
value = result; |
|
intLen = resultLen; |
|
offset = value.length - resultLen; |
|
normalize(); |
|
return sign; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int difference(MutableBigInteger b) { |
|
MutableBigInteger a = this; |
|
int sign = a.compare(b); |
|
if (sign == 0) |
|
return 0; |
|
if (sign < 0) { |
|
MutableBigInteger tmp = a; |
|
a = b; |
|
b = tmp; |
|
} |
|
|
|
long diff = 0; |
|
int x = a.intLen; |
|
int y = b.intLen; |
|
|
|
|
|
while (y > 0) { |
|
x--; y--; |
|
diff = (a.value[a.offset+ x] & LONG_MASK) - |
|
(b.value[b.offset+ y] & LONG_MASK) - ((int)-(diff>>32)); |
|
a.value[a.offset+x] = (int)diff; |
|
} |
|
|
|
while (x > 0) { |
|
x--; |
|
diff = (a.value[a.offset+ x] & LONG_MASK) - ((int)-(diff>>32)); |
|
a.value[a.offset+x] = (int)diff; |
|
} |
|
|
|
a.normalize(); |
|
return sign; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void multiply(MutableBigInteger y, MutableBigInteger z) { |
|
int xLen = intLen; |
|
int yLen = y.intLen; |
|
int newLen = xLen + yLen; |
|
|
|
|
|
if (z.value.length < newLen) |
|
z.value = new int[newLen]; |
|
z.offset = 0; |
|
z.intLen = newLen; |
|
|
|
|
|
long carry = 0; |
|
for (int j=yLen-1, k=yLen+xLen-1; j >= 0; j--, k--) { |
|
long product = (y.value[j+y.offset] & LONG_MASK) * |
|
(value[xLen-1+offset] & LONG_MASK) + carry; |
|
z.value[k] = (int)product; |
|
carry = product >>> 32; |
|
} |
|
z.value[xLen-1] = (int)carry; |
|
|
|
|
|
for (int i = xLen-2; i >= 0; i--) { |
|
carry = 0; |
|
for (int j=yLen-1, k=yLen+i; j >= 0; j--, k--) { |
|
long product = (y.value[j+y.offset] & LONG_MASK) * |
|
(value[i+offset] & LONG_MASK) + |
|
(z.value[k] & LONG_MASK) + carry; |
|
z.value[k] = (int)product; |
|
carry = product >>> 32; |
|
} |
|
z.value[i] = (int)carry; |
|
} |
|
|
|
|
|
z.normalize(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void mul(int y, MutableBigInteger z) { |
|
if (y == 1) { |
|
z.copyValue(this); |
|
return; |
|
} |
|
|
|
if (y == 0) { |
|
z.clear(); |
|
return; |
|
} |
|
|
|
|
|
long ylong = y & LONG_MASK; |
|
int[] zval = (z.value.length < intLen+1 ? new int[intLen + 1] |
|
: z.value); |
|
long carry = 0; |
|
for (int i = intLen-1; i >= 0; i--) { |
|
long product = ylong * (value[i+offset] & LONG_MASK) + carry; |
|
zval[i+1] = (int)product; |
|
carry = product >>> 32; |
|
} |
|
|
|
if (carry == 0) { |
|
z.offset = 1; |
|
z.intLen = intLen; |
|
} else { |
|
z.offset = 0; |
|
z.intLen = intLen + 1; |
|
zval[0] = (int)carry; |
|
} |
|
z.value = zval; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
int divideOneWord(int divisor, MutableBigInteger quotient) { |
|
long divisorLong = divisor & LONG_MASK; |
|
|
|
|
|
if (intLen == 1) { |
|
long dividendValue = value[offset] & LONG_MASK; |
|
int q = (int) (dividendValue / divisorLong); |
|
int r = (int) (dividendValue - q * divisorLong); |
|
quotient.value[0] = q; |
|
quotient.intLen = (q == 0) ? 0 : 1; |
|
quotient.offset = 0; |
|
return r; |
|
} |
|
|
|
if (quotient.value.length < intLen) |
|
quotient.value = new int[intLen]; |
|
quotient.offset = 0; |
|
quotient.intLen = intLen; |
|
|
|
|
|
int shift = Integer.numberOfLeadingZeros(divisor); |
|
|
|
int rem = value[offset]; |
|
long remLong = rem & LONG_MASK; |
|
if (remLong < divisorLong) { |
|
quotient.value[0] = 0; |
|
} else { |
|
quotient.value[0] = (int)(remLong / divisorLong); |
|
rem = (int) (remLong - (quotient.value[0] * divisorLong)); |
|
remLong = rem & LONG_MASK; |
|
} |
|
int xlen = intLen; |
|
while (--xlen > 0) { |
|
long dividendEstimate = (remLong << 32) | |
|
(value[offset + intLen - xlen] & LONG_MASK); |
|
int q; |
|
if (dividendEstimate >= 0) { |
|
q = (int) (dividendEstimate / divisorLong); |
|
rem = (int) (dividendEstimate - q * divisorLong); |
|
} else { |
|
long tmp = divWord(dividendEstimate, divisor); |
|
q = (int) (tmp & LONG_MASK); |
|
rem = (int) (tmp >>> 32); |
|
} |
|
quotient.value[intLen - xlen] = q; |
|
remLong = rem & LONG_MASK; |
|
} |
|
|
|
quotient.normalize(); |
|
|
|
if (shift > 0) |
|
return rem % divisor; |
|
else |
|
return rem; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) { |
|
return divide(b,quotient,true); |
|
} |
|
|
|
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needRemainder) { |
|
if (b.intLen < BigInteger.BURNIKEL_ZIEGLER_THRESHOLD || |
|
intLen - b.intLen < BigInteger.BURNIKEL_ZIEGLER_OFFSET) { |
|
return divideKnuth(b, quotient, needRemainder); |
|
} else { |
|
return divideAndRemainderBurnikelZiegler(b, quotient); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger divideKnuth(MutableBigInteger b, MutableBigInteger quotient) { |
|
return divideKnuth(b,quotient,true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger divideKnuth(MutableBigInteger b, MutableBigInteger quotient, boolean needRemainder) { |
|
if (b.intLen == 0) |
|
throw new ArithmeticException("BigInteger divide by zero"); |
|
|
|
|
|
if (intLen == 0) { |
|
quotient.intLen = quotient.offset = 0; |
|
return needRemainder ? new MutableBigInteger() : null; |
|
} |
|
|
|
int cmp = compare(b); |
|
|
|
if (cmp < 0) { |
|
quotient.intLen = quotient.offset = 0; |
|
return needRemainder ? new MutableBigInteger(this) : null; |
|
} |
|
|
|
if (cmp == 0) { |
|
quotient.value[0] = quotient.intLen = 1; |
|
quotient.offset = 0; |
|
return needRemainder ? new MutableBigInteger() : null; |
|
} |
|
|
|
quotient.clear(); |
|
|
|
if (b.intLen == 1) { |
|
int r = divideOneWord(b.value[b.offset], quotient); |
|
if(needRemainder) { |
|
if (r == 0) |
|
return new MutableBigInteger(); |
|
return new MutableBigInteger(r); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
if (intLen >= KNUTH_POW2_THRESH_LEN) { |
|
int trailingZeroBits = Math.min(getLowestSetBit(), b.getLowestSetBit()); |
|
if (trailingZeroBits >= KNUTH_POW2_THRESH_ZEROS*32) { |
|
MutableBigInteger a = new MutableBigInteger(this); |
|
b = new MutableBigInteger(b); |
|
a.rightShift(trailingZeroBits); |
|
b.rightShift(trailingZeroBits); |
|
MutableBigInteger r = a.divideKnuth(b, quotient); |
|
r.leftShift(trailingZeroBits); |
|
return r; |
|
} |
|
} |
|
|
|
return divideMagnitude(b, quotient, needRemainder); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger divideAndRemainderBurnikelZiegler(MutableBigInteger b, MutableBigInteger quotient) { |
|
int r = intLen; |
|
int s = b.intLen; |
|
|
|
|
|
quotient.offset = quotient.intLen = 0; |
|
|
|
if (r < s) { |
|
return this; |
|
} else { |
|
// Unlike Knuth division, we don't check for common powers of two here because |
|
// BZ already runs faster if both numbers contain powers of two and cancelling them has no |
|
// additional benefit. |
|
|
|
|
|
int m = 1 << (32-Integer.numberOfLeadingZeros(s/BigInteger.BURNIKEL_ZIEGLER_THRESHOLD)); |
|
|
|
int j = (s+m-1) / m; |
|
int n = j * m; |
|
long n32 = 32L * n; |
|
int sigma = (int) Math.max(0, n32 - b.bitLength()); |
|
MutableBigInteger bShifted = new MutableBigInteger(b); |
|
bShifted.safeLeftShift(sigma); |
|
MutableBigInteger aShifted = new MutableBigInteger (this); |
|
aShifted.safeLeftShift(sigma); |
|
|
|
|
|
int t = (int) ((aShifted.bitLength()+n32) / n32); |
|
if (t < 2) { |
|
t = 2; |
|
} |
|
|
|
// step 6: conceptually split a into blocks a[t-1], ..., a[0] |
|
MutableBigInteger a1 = aShifted.getBlock(t-1, t, n); |
|
|
|
// step 7: z[t-2] = [a[t-1], a[t-2]] |
|
MutableBigInteger z = aShifted.getBlock(t-2, t, n); |
|
z.addDisjoint(a1, n); |
|
|
|
|
|
MutableBigInteger qi = new MutableBigInteger(); |
|
MutableBigInteger ri; |
|
for (int i=t-2; i > 0; i--) { |
|
|
|
ri = z.divide2n1n(bShifted, qi); |
|
|
|
// step 8b: z = [ri, a[i-1]] |
|
z = aShifted.getBlock(i-1, t, n); |
|
z.addDisjoint(ri, n); |
|
quotient.addShifted(qi, i*n); |
|
} |
|
|
|
ri = z.divide2n1n(bShifted, qi); |
|
quotient.add(qi); |
|
|
|
ri.rightShift(sigma); |
|
return ri; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger divide2n1n(MutableBigInteger b, MutableBigInteger quotient) { |
|
int n = b.intLen; |
|
|
|
|
|
if (n%2 != 0 || n < BigInteger.BURNIKEL_ZIEGLER_THRESHOLD) { |
|
return divideKnuth(b, quotient); |
|
} |
|
|
|
|
|
MutableBigInteger aUpper = new MutableBigInteger(this); |
|
aUpper.safeRightShift(32*(n/2)); |
|
keepLower(n/2); |
|
|
|
|
|
MutableBigInteger q1 = new MutableBigInteger(); |
|
MutableBigInteger r1 = aUpper.divide3n2n(b, q1); |
|
|
|
// step 4: quotient=[r1,this]/b, r2=[r1,this]%b |
|
addDisjoint(r1, n/2); |
|
MutableBigInteger r2 = divide3n2n(b, quotient); |
|
|
|
|
|
quotient.addDisjoint(q1, n/2); |
|
return r2; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger divide3n2n(MutableBigInteger b, MutableBigInteger quotient) { |
|
int n = b.intLen / 2; |
|
|
|
|
|
MutableBigInteger a12 = new MutableBigInteger(this); |
|
a12.safeRightShift(32*n); |
|
|
|
|
|
MutableBigInteger b1 = new MutableBigInteger(b); |
|
b1.safeRightShift(n * 32); |
|
BigInteger b2 = b.getLower(n); |
|
|
|
MutableBigInteger r; |
|
MutableBigInteger d; |
|
if (compareShifted(b, n) < 0) { |
|
|
|
r = a12.divide2n1n(b1, quotient); |
|
|
|
|
|
d = new MutableBigInteger(quotient.toBigInteger().multiply(b2)); |
|
} else { |
|
|
|
quotient.ones(n); |
|
a12.add(b1); |
|
b1.leftShift(32*n); |
|
a12.subtract(b1); |
|
r = a12; |
|
|
|
|
|
d = new MutableBigInteger(b2); |
|
d.leftShift(32 * n); |
|
d.subtract(new MutableBigInteger(b2)); |
|
} |
|
|
|
// step 5: r = r*beta^n + a3 - d (paper says a4) |
|
|
|
r.leftShift(32 * n); |
|
r.addLower(this, n); |
|
|
|
|
|
while (r.compare(d) < 0) { |
|
r.add(b); |
|
quotient.subtract(MutableBigInteger.ONE); |
|
} |
|
r.subtract(d); |
|
|
|
return r; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger getBlock(int index, int numBlocks, int blockLength) { |
|
int blockStart = index * blockLength; |
|
if (blockStart >= intLen) { |
|
return new MutableBigInteger(); |
|
} |
|
|
|
int blockEnd; |
|
if (index == numBlocks-1) { |
|
blockEnd = intLen; |
|
} else { |
|
blockEnd = (index+1) * blockLength; |
|
} |
|
if (blockEnd > intLen) { |
|
return new MutableBigInteger(); |
|
} |
|
|
|
int[] newVal = Arrays.copyOfRange(value, offset+intLen-blockEnd, offset+intLen-blockStart); |
|
return new MutableBigInteger(newVal); |
|
} |
|
|
|
|
|
long bitLength() { |
|
if (intLen == 0) |
|
return 0; |
|
return intLen*32L - Integer.numberOfLeadingZeros(value[offset]); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
long divide(long v, MutableBigInteger quotient) { |
|
if (v == 0) |
|
throw new ArithmeticException("BigInteger divide by zero"); |
|
|
|
|
|
if (intLen == 0) { |
|
quotient.intLen = quotient.offset = 0; |
|
return 0; |
|
} |
|
if (v < 0) |
|
v = -v; |
|
|
|
int d = (int)(v >>> 32); |
|
quotient.clear(); |
|
|
|
if (d == 0) |
|
return divideOneWord((int)v, quotient) & LONG_MASK; |
|
else { |
|
return divideLongMagnitude(v, quotient).toLong(); |
|
} |
|
} |
|
|
|
private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift) { |
|
int n2 = 32 - shift; |
|
int c=src[srcFrom]; |
|
for (int i=0; i < srcLen-1; i++) { |
|
int b = c; |
|
c = src[++srcFrom]; |
|
dst[dstFrom+i] = (b << shift) | (c >>> n2); |
|
} |
|
dst[dstFrom+srcLen-1] = c << shift; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger divideMagnitude(MutableBigInteger div, |
|
MutableBigInteger quotient, |
|
boolean needRemainder ) { |
|
// assert div.intLen > 1 |
|
|
|
int shift = Integer.numberOfLeadingZeros(div.value[div.offset]); |
|
|
|
final int dlen = div.intLen; |
|
int[] divisor; |
|
MutableBigInteger rem; |
|
if (shift > 0) { |
|
divisor = new int[dlen]; |
|
copyAndShift(div.value,div.offset,dlen,divisor,0,shift); |
|
if (Integer.numberOfLeadingZeros(value[offset]) >= shift) { |
|
int[] remarr = new int[intLen + 1]; |
|
rem = new MutableBigInteger(remarr); |
|
rem.intLen = intLen; |
|
rem.offset = 1; |
|
copyAndShift(value,offset,intLen,remarr,1,shift); |
|
} else { |
|
int[] remarr = new int[intLen + 2]; |
|
rem = new MutableBigInteger(remarr); |
|
rem.intLen = intLen+1; |
|
rem.offset = 1; |
|
int rFrom = offset; |
|
int c=0; |
|
int n2 = 32 - shift; |
|
for (int i=1; i < intLen+1; i++,rFrom++) { |
|
int b = c; |
|
c = value[rFrom]; |
|
remarr[i] = (b << shift) | (c >>> n2); |
|
} |
|
remarr[intLen+1] = c << shift; |
|
} |
|
} else { |
|
divisor = Arrays.copyOfRange(div.value, div.offset, div.offset + div.intLen); |
|
rem = new MutableBigInteger(new int[intLen + 1]); |
|
System.arraycopy(value, offset, rem.value, 1, intLen); |
|
rem.intLen = intLen; |
|
rem.offset = 1; |
|
} |
|
|
|
int nlen = rem.intLen; |
|
|
|
|
|
final int limit = nlen - dlen + 1; |
|
if (quotient.value.length < limit) { |
|
quotient.value = new int[limit]; |
|
quotient.offset = 0; |
|
} |
|
quotient.intLen = limit; |
|
int[] q = quotient.value; |
|
|
|
|
|
|
|
if (rem.intLen == nlen) { |
|
rem.offset = 0; |
|
rem.value[0] = 0; |
|
rem.intLen++; |
|
} |
|
|
|
int dh = divisor[0]; |
|
long dhLong = dh & LONG_MASK; |
|
int dl = divisor[1]; |
|
|
|
|
|
for (int j=0; j < limit-1; j++) { |
|
// D3 Calculate qhat |
|
|
|
int qhat = 0; |
|
int qrem = 0; |
|
boolean skipCorrection = false; |
|
int nh = rem.value[j+rem.offset]; |
|
int nh2 = nh + 0x80000000; |
|
int nm = rem.value[j+1+rem.offset]; |
|
|
|
if (nh == dh) { |
|
qhat = ~0; |
|
qrem = nh + nm; |
|
skipCorrection = qrem + 0x80000000 < nh2; |
|
} else { |
|
long nChunk = (((long)nh) << 32) | (nm & LONG_MASK); |
|
if (nChunk >= 0) { |
|
qhat = (int) (nChunk / dhLong); |
|
qrem = (int) (nChunk - (qhat * dhLong)); |
|
} else { |
|
long tmp = divWord(nChunk, dh); |
|
qhat = (int) (tmp & LONG_MASK); |
|
qrem = (int) (tmp >>> 32); |
|
} |
|
} |
|
|
|
if (qhat == 0) |
|
continue; |
|
|
|
if (!skipCorrection) { |
|
long nl = rem.value[j+2+rem.offset] & LONG_MASK; |
|
long rs = ((qrem & LONG_MASK) << 32) | nl; |
|
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); |
|
|
|
if (unsignedLongCompare(estProduct, rs)) { |
|
qhat--; |
|
qrem = (int)((qrem & LONG_MASK) + dhLong); |
|
if ((qrem & LONG_MASK) >= dhLong) { |
|
estProduct -= (dl & LONG_MASK); |
|
rs = ((qrem & LONG_MASK) << 32) | nl; |
|
if (unsignedLongCompare(estProduct, rs)) |
|
qhat--; |
|
} |
|
} |
|
} |
|
|
|
|
|
rem.value[j+rem.offset] = 0; |
|
int borrow = mulsub(rem.value, divisor, qhat, dlen, j+rem.offset); |
|
|
|
|
|
if (borrow + 0x80000000 > nh2) { |
|
|
|
divadd(divisor, rem.value, j+1+rem.offset); |
|
qhat--; |
|
} |
|
|
|
|
|
q[j] = qhat; |
|
} // D7 loop on j |
|
// D3 Calculate qhat |
|
|
|
int qhat = 0; |
|
int qrem = 0; |
|
boolean skipCorrection = false; |
|
int nh = rem.value[limit - 1 + rem.offset]; |
|
int nh2 = nh + 0x80000000; |
|
int nm = rem.value[limit + rem.offset]; |
|
|
|
if (nh == dh) { |
|
qhat = ~0; |
|
qrem = nh + nm; |
|
skipCorrection = qrem + 0x80000000 < nh2; |
|
} else { |
|
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK); |
|
if (nChunk >= 0) { |
|
qhat = (int) (nChunk / dhLong); |
|
qrem = (int) (nChunk - (qhat * dhLong)); |
|
} else { |
|
long tmp = divWord(nChunk, dh); |
|
qhat = (int) (tmp & LONG_MASK); |
|
qrem = (int) (tmp >>> 32); |
|
} |
|
} |
|
if (qhat != 0) { |
|
if (!skipCorrection) { |
|
long nl = rem.value[limit + 1 + rem.offset] & LONG_MASK; |
|
long rs = ((qrem & LONG_MASK) << 32) | nl; |
|
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); |
|
|
|
if (unsignedLongCompare(estProduct, rs)) { |
|
qhat--; |
|
qrem = (int) ((qrem & LONG_MASK) + dhLong); |
|
if ((qrem & LONG_MASK) >= dhLong) { |
|
estProduct -= (dl & LONG_MASK); |
|
rs = ((qrem & LONG_MASK) << 32) | nl; |
|
if (unsignedLongCompare(estProduct, rs)) |
|
qhat--; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
int borrow; |
|
rem.value[limit - 1 + rem.offset] = 0; |
|
if(needRemainder) |
|
borrow = mulsub(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset); |
|
else |
|
borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset); |
|
|
|
|
|
if (borrow + 0x80000000 > nh2) { |
|
|
|
if(needRemainder) |
|
divadd(divisor, rem.value, limit - 1 + 1 + rem.offset); |
|
qhat--; |
|
} |
|
|
|
|
|
q[(limit - 1)] = qhat; |
|
} |
|
|
|
|
|
if (needRemainder) { |
|
|
|
if (shift > 0) |
|
rem.rightShift(shift); |
|
rem.normalize(); |
|
} |
|
quotient.normalize(); |
|
return needRemainder ? rem : null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger divideLongMagnitude(long ldivisor, MutableBigInteger quotient) { |
|
|
|
MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]); |
|
System.arraycopy(value, offset, rem.value, 1, intLen); |
|
rem.intLen = intLen; |
|
rem.offset = 1; |
|
|
|
int nlen = rem.intLen; |
|
|
|
int limit = nlen - 2 + 1; |
|
if (quotient.value.length < limit) { |
|
quotient.value = new int[limit]; |
|
quotient.offset = 0; |
|
} |
|
quotient.intLen = limit; |
|
int[] q = quotient.value; |
|
|
|
|
|
int shift = Long.numberOfLeadingZeros(ldivisor); |
|
if (shift > 0) { |
|
ldivisor<<=shift; |
|
rem.leftShift(shift); |
|
} |
|
|
|
|
|
if (rem.intLen == nlen) { |
|
rem.offset = 0; |
|
rem.value[0] = 0; |
|
rem.intLen++; |
|
} |
|
|
|
int dh = (int)(ldivisor >>> 32); |
|
long dhLong = dh & LONG_MASK; |
|
int dl = (int)(ldivisor & LONG_MASK); |
|
|
|
|
|
for (int j = 0; j < limit; j++) { |
|
// D3 Calculate qhat |
|
|
|
int qhat = 0; |
|
int qrem = 0; |
|
boolean skipCorrection = false; |
|
int nh = rem.value[j + rem.offset]; |
|
int nh2 = nh + 0x80000000; |
|
int nm = rem.value[j + 1 + rem.offset]; |
|
|
|
if (nh == dh) { |
|
qhat = ~0; |
|
qrem = nh + nm; |
|
skipCorrection = qrem + 0x80000000 < nh2; |
|
} else { |
|
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK); |
|
if (nChunk >= 0) { |
|
qhat = (int) (nChunk / dhLong); |
|
qrem = (int) (nChunk - (qhat * dhLong)); |
|
} else { |
|
long tmp = divWord(nChunk, dh); |
|
qhat =(int)(tmp & LONG_MASK); |
|
qrem = (int)(tmp>>>32); |
|
} |
|
} |
|
|
|
if (qhat == 0) |
|
continue; |
|
|
|
if (!skipCorrection) { |
|
long nl = rem.value[j + 2 + rem.offset] & LONG_MASK; |
|
long rs = ((qrem & LONG_MASK) << 32) | nl; |
|
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); |
|
|
|
if (unsignedLongCompare(estProduct, rs)) { |
|
qhat--; |
|
qrem = (int) ((qrem & LONG_MASK) + dhLong); |
|
if ((qrem & LONG_MASK) >= dhLong) { |
|
estProduct -= (dl & LONG_MASK); |
|
rs = ((qrem & LONG_MASK) << 32) | nl; |
|
if (unsignedLongCompare(estProduct, rs)) |
|
qhat--; |
|
} |
|
} |
|
} |
|
|
|
|
|
rem.value[j + rem.offset] = 0; |
|
int borrow = mulsubLong(rem.value, dh, dl, qhat, j + rem.offset); |
|
|
|
|
|
if (borrow + 0x80000000 > nh2) { |
|
|
|
divaddLong(dh,dl, rem.value, j + 1 + rem.offset); |
|
qhat--; |
|
} |
|
|
|
|
|
q[j] = qhat; |
|
} // D7 loop on j |
|
|
|
|
|
if (shift > 0) |
|
rem.rightShift(shift); |
|
|
|
quotient.normalize(); |
|
rem.normalize(); |
|
return rem; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int divaddLong(int dh, int dl, int[] result, int offset) { |
|
long carry = 0; |
|
|
|
long sum = (dl & LONG_MASK) + (result[1+offset] & LONG_MASK); |
|
result[1+offset] = (int)sum; |
|
|
|
sum = (dh & LONG_MASK) + (result[offset] & LONG_MASK) + carry; |
|
result[offset] = (int)sum; |
|
carry = sum >>> 32; |
|
return (int)carry; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int mulsubLong(int[] q, int dh, int dl, int x, int offset) { |
|
long xLong = x & LONG_MASK; |
|
offset += 2; |
|
long product = (dl & LONG_MASK) * xLong; |
|
long difference = q[offset] - product; |
|
q[offset--] = (int)difference; |
|
long carry = (product >>> 32) |
|
+ (((difference & LONG_MASK) > |
|
(((~(int)product) & LONG_MASK))) ? 1:0); |
|
product = (dh & LONG_MASK) * xLong + carry; |
|
difference = q[offset] - product; |
|
q[offset--] = (int)difference; |
|
carry = (product >>> 32) |
|
+ (((difference & LONG_MASK) > |
|
(((~(int)product) & LONG_MASK))) ? 1:0); |
|
return (int)carry; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean unsignedLongCompare(long one, long two) { |
|
return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static long divWord(long n, int d) { |
|
long dLong = d & LONG_MASK; |
|
long r; |
|
long q; |
|
if (dLong == 1) { |
|
q = (int)n; |
|
r = 0; |
|
return (r << 32) | (q & LONG_MASK); |
|
} |
|
|
|
|
|
q = (n >>> 1) / (dLong >>> 1); |
|
r = n - q*dLong; |
|
|
|
|
|
while (r < 0) { |
|
r += dLong; |
|
q--; |
|
} |
|
while (r >= dLong) { |
|
r -= dLong; |
|
q++; |
|
} |
|
|
|
return (r << 32) | (q & LONG_MASK); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger sqrt() { |
|
|
|
if (this.isZero()) { |
|
return new MutableBigInteger(0); |
|
} else if (this.value.length == 1 |
|
&& (this.value[0] & LONG_MASK) < 4) { |
|
return ONE; |
|
} |
|
|
|
if (bitLength() <= 63) { |
|
|
|
long v = new BigInteger(this.value, 1).longValueExact(); |
|
long xk = (long)Math.floor(Math.sqrt(v)); |
|
|
|
|
|
do { |
|
long xk1 = (xk + v/xk)/2; |
|
|
|
|
|
if (xk1 >= xk) { |
|
return new MutableBigInteger(new int[] { |
|
(int)(xk >>> 32), (int)(xk & LONG_MASK) |
|
}); |
|
} |
|
|
|
xk = xk1; |
|
} while (true); |
|
} else { |
|
// Set up the initial estimate of the iteration. |
|
|
|
|
|
int bitLength = (int) this.bitLength(); |
|
if (bitLength != this.bitLength()) { |
|
throw new ArithmeticException("bitLength() integer overflow"); |
|
} |
|
|
|
|
|
int shift = bitLength - 63; |
|
if (shift % 2 == 1) { |
|
shift++; |
|
} |
|
|
|
|
|
MutableBigInteger xk = new MutableBigInteger(this); |
|
xk.rightShift(shift); |
|
xk.normalize(); |
|
|
|
|
|
double d = new BigInteger(xk.value, 1).doubleValue(); |
|
BigInteger bi = BigInteger.valueOf((long)Math.ceil(Math.sqrt(d))); |
|
xk = new MutableBigInteger(bi.mag); |
|
|
|
|
|
xk.leftShift(shift / 2); |
|
|
|
|
|
MutableBigInteger xk1 = new MutableBigInteger(); |
|
do { |
|
|
|
this.divide(xk, xk1, false); |
|
xk1.add(xk); |
|
xk1.rightShift(1); |
|
|
|
|
|
if (xk1.compare(xk) >= 0) { |
|
return xk; |
|
} |
|
|
|
|
|
xk.copyValue(xk1); |
|
|
|
xk1.reset(); |
|
} while (true); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger hybridGCD(MutableBigInteger b) { |
|
// Use Euclid's algorithm until the numbers are approximately the |
|
|
|
MutableBigInteger a = this; |
|
MutableBigInteger q = new MutableBigInteger(); |
|
|
|
while (b.intLen != 0) { |
|
if (Math.abs(a.intLen - b.intLen) < 2) |
|
return a.binaryGCD(b); |
|
|
|
MutableBigInteger r = a.divide(b, q); |
|
a = b; |
|
b = r; |
|
} |
|
return a; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger binaryGCD(MutableBigInteger v) { |
|
|
|
MutableBigInteger u = this; |
|
MutableBigInteger r = new MutableBigInteger(); |
|
|
|
|
|
int s1 = u.getLowestSetBit(); |
|
int s2 = v.getLowestSetBit(); |
|
int k = (s1 < s2) ? s1 : s2; |
|
if (k != 0) { |
|
u.rightShift(k); |
|
v.rightShift(k); |
|
} |
|
|
|
|
|
boolean uOdd = (k == s1); |
|
MutableBigInteger t = uOdd ? v: u; |
|
int tsign = uOdd ? -1 : 1; |
|
|
|
int lb; |
|
while ((lb = t.getLowestSetBit()) >= 0) { |
|
|
|
t.rightShift(lb); |
|
|
|
if (tsign > 0) |
|
u = t; |
|
else |
|
v = t; |
|
|
|
|
|
if (u.intLen < 2 && v.intLen < 2) { |
|
int x = u.value[u.offset]; |
|
int y = v.value[v.offset]; |
|
x = binaryGcd(x, y); |
|
r.value[0] = x; |
|
r.intLen = 1; |
|
r.offset = 0; |
|
if (k > 0) |
|
r.leftShift(k); |
|
return r; |
|
} |
|
|
|
|
|
if ((tsign = u.difference(v)) == 0) |
|
break; |
|
t = (tsign >= 0) ? u : v; |
|
} |
|
|
|
if (k > 0) |
|
u.leftShift(k); |
|
return u; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static int binaryGcd(int a, int b) { |
|
if (b == 0) |
|
return a; |
|
if (a == 0) |
|
return b; |
|
|
|
|
|
int aZeros = Integer.numberOfTrailingZeros(a); |
|
int bZeros = Integer.numberOfTrailingZeros(b); |
|
a >>>= aZeros; |
|
b >>>= bZeros; |
|
|
|
int t = (aZeros < bZeros ? aZeros : bZeros); |
|
|
|
while (a != b) { |
|
if ((a+0x80000000) > (b+0x80000000)) { |
|
a -= b; |
|
a >>>= Integer.numberOfTrailingZeros(a); |
|
} else { |
|
b -= a; |
|
b >>>= Integer.numberOfTrailingZeros(b); |
|
} |
|
} |
|
return a<<t; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger mutableModInverse(MutableBigInteger p) { |
|
|
|
if (p.isOdd()) |
|
return modInverse(p); |
|
|
|
|
|
if (isEven()) |
|
throw new ArithmeticException("BigInteger not invertible."); |
|
|
|
|
|
int powersOf2 = p.getLowestSetBit(); |
|
|
|
|
|
MutableBigInteger oddMod = new MutableBigInteger(p); |
|
oddMod.rightShift(powersOf2); |
|
|
|
if (oddMod.isOne()) |
|
return modInverseMP2(powersOf2); |
|
|
|
|
|
MutableBigInteger oddPart = modInverse(oddMod); |
|
|
|
|
|
MutableBigInteger evenPart = modInverseMP2(powersOf2); |
|
|
|
|
|
MutableBigInteger y1 = modInverseBP2(oddMod, powersOf2); |
|
MutableBigInteger y2 = oddMod.modInverseMP2(powersOf2); |
|
|
|
MutableBigInteger temp1 = new MutableBigInteger(); |
|
MutableBigInteger temp2 = new MutableBigInteger(); |
|
MutableBigInteger result = new MutableBigInteger(); |
|
|
|
oddPart.leftShift(powersOf2); |
|
oddPart.multiply(y1, result); |
|
|
|
evenPart.multiply(oddMod, temp1); |
|
temp1.multiply(y2, temp2); |
|
|
|
result.add(temp2); |
|
return result.divide(p, temp1); |
|
} |
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger modInverseMP2(int k) { |
|
if (isEven()) |
|
throw new ArithmeticException("Non-invertible. (GCD != 1)"); |
|
|
|
if (k > 64) |
|
return euclidModInverse(k); |
|
|
|
int t = inverseMod32(value[offset+intLen-1]); |
|
|
|
if (k < 33) { |
|
t = (k == 32 ? t : t & ((1 << k) - 1)); |
|
return new MutableBigInteger(t); |
|
} |
|
|
|
long pLong = (value[offset+intLen-1] & LONG_MASK); |
|
if (intLen > 1) |
|
pLong |= ((long)value[offset+intLen-2] << 32); |
|
long tLong = t & LONG_MASK; |
|
tLong = tLong * (2 - pLong * tLong); |
|
tLong = (k == 64 ? tLong : tLong & ((1L << k) - 1)); |
|
|
|
MutableBigInteger result = new MutableBigInteger(new int[2]); |
|
result.value[0] = (int)(tLong >>> 32); |
|
result.value[1] = (int)tLong; |
|
result.intLen = 2; |
|
result.normalize(); |
|
return result; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static int inverseMod32(int val) { |
|
|
|
int t = val; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
return t; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static long inverseMod64(long val) { |
|
|
|
long t = val; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
t *= 2 - val*t; |
|
assert(t * val == 1); |
|
return t; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static MutableBigInteger modInverseBP2(MutableBigInteger mod, int k) { |
|
|
|
return fixup(new MutableBigInteger(1), new MutableBigInteger(mod), k); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private MutableBigInteger modInverse(MutableBigInteger mod) { |
|
MutableBigInteger p = new MutableBigInteger(mod); |
|
MutableBigInteger f = new MutableBigInteger(this); |
|
MutableBigInteger g = new MutableBigInteger(p); |
|
SignedMutableBigInteger c = new SignedMutableBigInteger(1); |
|
SignedMutableBigInteger d = new SignedMutableBigInteger(); |
|
MutableBigInteger temp = null; |
|
SignedMutableBigInteger sTemp = null; |
|
|
|
int k = 0; |
|
|
|
if (f.isEven()) { |
|
int trailingZeros = f.getLowestSetBit(); |
|
f.rightShift(trailingZeros); |
|
d.leftShift(trailingZeros); |
|
k = trailingZeros; |
|
} |
|
|
|
|
|
while (!f.isOne()) { |
|
|
|
if (f.isZero()) |
|
throw new ArithmeticException("BigInteger not invertible."); |
|
|
|
|
|
if (f.compare(g) < 0) { |
|
temp = f; f = g; g = temp; |
|
sTemp = d; d = c; c = sTemp; |
|
} |
|
|
|
|
|
if (((f.value[f.offset + f.intLen - 1] ^ |
|
g.value[g.offset + g.intLen - 1]) & 3) == 0) { |
|
f.subtract(g); |
|
c.signedSubtract(d); |
|
} else { |
|
f.add(g); |
|
c.signedAdd(d); |
|
} |
|
|
|
|
|
int trailingZeros = f.getLowestSetBit(); |
|
f.rightShift(trailingZeros); |
|
d.leftShift(trailingZeros); |
|
k += trailingZeros; |
|
} |
|
|
|
while (c.sign < 0) |
|
c.signedAdd(p); |
|
|
|
return fixup(c, p, k); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static MutableBigInteger fixup(MutableBigInteger c, MutableBigInteger p, |
|
int k) { |
|
MutableBigInteger temp = new MutableBigInteger(); |
|
|
|
int r = -inverseMod32(p.value[p.offset+p.intLen-1]); |
|
|
|
for (int i=0, numWords = k >> 5; i < numWords; i++) { |
|
|
|
int v = r * c.value[c.offset + c.intLen-1]; |
|
|
|
p.mul(v, temp); |
|
c.add(temp); |
|
|
|
c.intLen--; |
|
} |
|
int numBits = k & 0x1f; |
|
if (numBits != 0) { |
|
|
|
int v = r * c.value[c.offset + c.intLen-1]; |
|
v &= ((1<<numBits) - 1); |
|
|
|
p.mul(v, temp); |
|
c.add(temp); |
|
|
|
c.rightShift(numBits); |
|
} |
|
|
|
|
|
while (c.compare(p) >= 0) |
|
c.subtract(p); |
|
|
|
return c; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
MutableBigInteger euclidModInverse(int k) { |
|
MutableBigInteger b = new MutableBigInteger(1); |
|
b.leftShift(k); |
|
MutableBigInteger mod = new MutableBigInteger(b); |
|
|
|
MutableBigInteger a = new MutableBigInteger(this); |
|
MutableBigInteger q = new MutableBigInteger(); |
|
MutableBigInteger r = b.divide(a, q); |
|
|
|
MutableBigInteger swapper = b; |
|
|
|
b = r; |
|
r = swapper; |
|
|
|
MutableBigInteger t1 = new MutableBigInteger(q); |
|
MutableBigInteger t0 = new MutableBigInteger(1); |
|
MutableBigInteger temp = new MutableBigInteger(); |
|
|
|
while (!b.isOne()) { |
|
r = a.divide(b, q); |
|
|
|
if (r.intLen == 0) |
|
throw new ArithmeticException("BigInteger not invertible."); |
|
|
|
swapper = r; |
|
a = swapper; |
|
|
|
if (q.intLen == 1) |
|
t1.mul(q.value[q.offset], temp); |
|
else |
|
q.multiply(t1, temp); |
|
swapper = q; |
|
q = temp; |
|
temp = swapper; |
|
t0.add(q); |
|
|
|
if (a.isOne()) |
|
return t0; |
|
|
|
r = b.divide(a, q); |
|
|
|
if (r.intLen == 0) |
|
throw new ArithmeticException("BigInteger not invertible."); |
|
|
|
swapper = b; |
|
b = r; |
|
|
|
if (q.intLen == 1) |
|
t0.mul(q.value[q.offset], temp); |
|
else |
|
q.multiply(t0, temp); |
|
swapper = q; q = temp; temp = swapper; |
|
|
|
t1.add(q); |
|
} |
|
mod.subtract(t1); |
|
return mod; |
|
} |
|
} |