|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package jdk.internal.math; |
|
|
|
import jdk.internal.misc.CDS; |
|
|
|
import java.math.BigInteger; |
|
import java.util.Arrays; |
|
//@ model import org.jmlspecs.models.JMLMath; |
|
|
|
|
|
|
|
*/ |
|
public class FDBigInteger { |
|
|
|
// |
|
// This class contains many comments that start with "/*@" mark. |
|
// They are behavourial specification in |
|
// the Java Modelling Language (JML): |
|
// http://www.eecs.ucf.edu/~leavens/JML//index.shtml |
|
// |
|
|
|
/*@ |
|
@ public pure model static \bigint UNSIGNED(int v) { |
|
@ return v >= 0 ? v : v + (((\bigint)1) << 32); |
|
@ } |
|
@ |
|
@ public pure model static \bigint UNSIGNED(long v) { |
|
@ return v >= 0 ? v : v + (((\bigint)1) << 64); |
|
@ } |
|
@ |
|
@ public pure model static \bigint AP(int[] data, int len) { |
|
@ return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32)); |
|
@ } |
|
@ |
|
@ public pure model static \bigint pow52(int p5, int p2) { |
|
@ ghost \bigint v = 1; |
|
@ for (int i = 0; i < p5; i++) v *= 5; |
|
@ return v << p2; |
|
@ } |
|
@ |
|
@ public pure model static \bigint pow10(int p10) { |
|
@ return pow52(p10, p10); |
|
@ } |
|
@*/ |
|
|
|
static final int[] SMALL_5_POW; |
|
|
|
static final long[] LONG_5_POW; |
|
|
|
|
|
private static final int MAX_FIVE_POW = 340; |
|
|
|
|
|
private static final FDBigInteger POW_5_CACHE[]; |
|
|
|
|
|
public static final FDBigInteger ZERO; |
|
|
|
|
|
private static Object[] archivedCaches; |
|
|
|
|
|
static { |
|
CDS.initializeFromArchive(FDBigInteger.class); |
|
Object[] caches = archivedCaches; |
|
if (caches == null) { |
|
long[] long5pow = { |
|
1L, |
|
5L, |
|
5L * 5, |
|
5L * 5 * 5, |
|
5L * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
}; |
|
int[] small5pow = { |
|
1, |
|
5, |
|
5 * 5, |
|
5 * 5 * 5, |
|
5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 |
|
}; |
|
FDBigInteger[] pow5cache = new FDBigInteger[MAX_FIVE_POW]; |
|
int i = 0; |
|
while (i < small5pow.length) { |
|
FDBigInteger pow5 = new FDBigInteger(new int[] { small5pow[i] }, 0); |
|
pow5.makeImmutable(); |
|
pow5cache[i] = pow5; |
|
i++; |
|
} |
|
FDBigInteger prev = pow5cache[i - 1]; |
|
while (i < MAX_FIVE_POW) { |
|
pow5cache[i] = prev = prev.mult(5); |
|
prev.makeImmutable(); |
|
i++; |
|
} |
|
FDBigInteger zero = new FDBigInteger(new int[0], 0); |
|
zero.makeImmutable(); |
|
archivedCaches = caches = new Object[] {small5pow, long5pow, pow5cache, zero}; |
|
} |
|
SMALL_5_POW = (int[])caches[0]; |
|
LONG_5_POW = (long[])caches[1]; |
|
POW_5_CACHE = (FDBigInteger[])caches[2]; |
|
ZERO = (FDBigInteger)caches[3]; |
|
} |
|
|
|
|
|
private static final long LONG_MASK = 0xffffffffL; |
|
|
|
//@ spec_public non_null; |
|
private int data[]; |
|
//@ spec_public; |
|
private int offset; |
|
//@ spec_public; |
|
private int nWords; |
|
// if nWords==0 -> this FDBigInteger is zero |
|
|
|
private boolean isImmutable = false; |
|
|
|
/*@ |
|
@ public invariant 0 <= nWords && nWords <= data.length && offset >= 0; |
|
@ public invariant nWords == 0 ==> offset == 0; |
|
@ public invariant nWords > 0 ==> data[nWords - 1] != 0; |
|
@ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0); |
|
@ public pure model \bigint value() { |
|
@ return AP(data, nWords) << (offset*32); |
|
@ } |
|
@*/ |
|
|
|
/** |
|
* Constructs an <code>FDBigInteger</code> from data and padding. The |
|
* <code>data</code> parameter has the least significant <code>int</code> at |
|
* the zeroth index. The <code>offset</code> parameter gives the number of |
|
* zero <code>int</code>s to be inferred below the least significant element |
|
* of <code>data</code>. |
|
* |
|
* @param data An array containing all non-zero <code>int</code>s of the value. |
|
* @param offset An offset indicating the number of zero <code>int</code>s to pad |
|
* below the least significant element of <code>data</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
private FDBigInteger(int[] data, int offset) { |
|
this.data = data; |
|
this.offset = offset; |
|
this.nWords = data.length; |
|
trimLeadingZeros(); |
|
} |
|
|
|
/** |
|
* Constructs an <code>FDBigInteger</code> from a starting value and some |
|
* decimal digits. |
|
* |
|
* @param lValue The starting value. |
|
* @param digits The decimal digits. |
|
* @param kDigits The initial index into <code>digits</code>. |
|
* @param nDigits The final index into <code>digits</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) { |
|
int n = Math.max((nDigits + 8) / 9, 2); |
|
data = new int[n]; |
|
data[0] = (int) lValue; |
|
data[1] = (int) (lValue >>> 32); |
|
offset = 0; |
|
nWords = 2; |
|
int i = kDigits; |
|
int limit = nDigits - 5; |
|
int v; |
|
while (i < limit) { |
|
int ilim = i + 5; |
|
v = (int) digits[i++] - (int) '0'; |
|
while (i < ilim) { |
|
v = 10 * v + (int) digits[i++] - (int) '0'; |
|
} |
|
multAddMe(100000, v); |
|
} |
|
int factor = 1; |
|
v = 0; |
|
while (i < nDigits) { |
|
v = 10 * v + (int) digits[i++] - (int) '0'; |
|
factor *= 10; |
|
} |
|
if (factor != 1) { |
|
multAddMe(factor, v); |
|
} |
|
trimLeadingZeros(); |
|
} |
|
|
|
/** |
|
* Returns an <code>FDBigInteger</code> with the numerical value |
|
* <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. |
|
* |
|
* @param p5 The exponent of the power-of-five factor. |
|
* @param p2 The exponent of the power-of-two factor. |
|
* @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code> |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
public static FDBigInteger valueOfPow52(int p5, int p2) { |
|
if (p5 != 0) { |
|
if (p2 == 0) { |
|
return big5pow(p5); |
|
} else if (p5 < SMALL_5_POW.length) { |
|
int pow5 = SMALL_5_POW[p5]; |
|
int wordcount = p2 >> 5; |
|
int bitcount = p2 & 0x1f; |
|
if (bitcount == 0) { |
|
return new FDBigInteger(new int[]{pow5}, wordcount); |
|
} else { |
|
return new FDBigInteger(new int[]{ |
|
pow5 << bitcount, |
|
pow5 >>> (32 - bitcount) |
|
}, wordcount); |
|
} |
|
} else { |
|
return big5pow(p5).leftShift(p2); |
|
} |
|
} else { |
|
return valueOfPow2(p2); |
|
} |
|
} |
|
|
|
/** |
|
* Returns an <code>FDBigInteger</code> with the numerical value |
|
* <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>. |
|
* |
|
* @param value The constant factor. |
|
* @param p5 The exponent of the power-of-five factor. |
|
* @param p2 The exponent of the power-of-two factor. |
|
* @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code> |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) { |
|
assert p5 >= 0 : p5; |
|
assert p2 >= 0 : p2; |
|
int v0 = (int) value; |
|
int v1 = (int) (value >>> 32); |
|
int wordcount = p2 >> 5; |
|
int bitcount = p2 & 0x1f; |
|
if (p5 != 0) { |
|
if (p5 < SMALL_5_POW.length) { |
|
long pow5 = SMALL_5_POW[p5] & LONG_MASK; |
|
long carry = (v0 & LONG_MASK) * pow5; |
|
v0 = (int) carry; |
|
carry >>>= 32; |
|
carry = (v1 & LONG_MASK) * pow5 + carry; |
|
v1 = (int) carry; |
|
int v2 = (int) (carry >>> 32); |
|
if (bitcount == 0) { |
|
return new FDBigInteger(new int[]{v0, v1, v2}, wordcount); |
|
} else { |
|
return new FDBigInteger(new int[]{ |
|
v0 << bitcount, |
|
(v1 << bitcount) | (v0 >>> (32 - bitcount)), |
|
(v2 << bitcount) | (v1 >>> (32 - bitcount)), |
|
v2 >>> (32 - bitcount) |
|
}, wordcount); |
|
} |
|
} else { |
|
FDBigInteger pow5 = big5pow(p5); |
|
int[] r; |
|
if (v1 == 0) { |
|
r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)]; |
|
mult(pow5.data, pow5.nWords, v0, r); |
|
} else { |
|
r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)]; |
|
mult(pow5.data, pow5.nWords, v0, v1, r); |
|
} |
|
return (new FDBigInteger(r, pow5.offset)).leftShift(p2); |
|
} |
|
} else if (p2 != 0) { |
|
if (bitcount == 0) { |
|
return new FDBigInteger(new int[]{v0, v1}, wordcount); |
|
} else { |
|
return new FDBigInteger(new int[]{ |
|
v0 << bitcount, |
|
(v1 << bitcount) | (v0 >>> (32 - bitcount)), |
|
v1 >>> (32 - bitcount) |
|
}, wordcount); |
|
} |
|
} |
|
return new FDBigInteger(new int[]{v0, v1}, 0); |
|
} |
|
|
|
/** |
|
* Returns an <code>FDBigInteger</code> with the numerical value |
|
* <code>2<sup>p2</sup></code>. |
|
* |
|
* @param p2 The exponent of 2. |
|
* @return <code>2<sup>p2</sup></code> |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
private static FDBigInteger valueOfPow2(int p2) { |
|
int wordcount = p2 >> 5; |
|
int bitcount = p2 & 0x1f; |
|
return new FDBigInteger(new int[]{1 << bitcount}, wordcount); |
|
} |
|
|
|
/** |
|
* Removes all leading zeros from this <code>FDBigInteger</code> adjusting |
|
* the offset and number of non-zero leading words accordingly. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private void trimLeadingZeros() { |
|
int i = nWords; |
|
if (i > 0 && (data[--i] == 0)) { |
|
|
|
while(i > 0 && data[i - 1] == 0) { |
|
i--; |
|
} |
|
this.nWords = i; |
|
if (i == 0) { |
|
this.offset = 0; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Retrieves the normalization bias of the <code>FDBigIntger</code>. The |
|
* normalization bias is a left shift such that after it the highest word |
|
* of the value will have the 4 highest bits equal to zero: |
|
* {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1 |
|
* {@code (highestWord & 0x08000000) != 0}. |
|
* |
|
* @return The normalization bias. |
|
*/ |
|
|
|
|
|
@*/ |
|
public int getNormalizationBias() { |
|
if (nWords == 0) { |
|
throw new IllegalArgumentException("Zero value cannot be normalized"); |
|
} |
|
int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]); |
|
return (zeros < 4) ? 28 + zeros : zeros - 4; |
|
} |
|
|
|
// TODO: Why is anticount param needed if it is always 32 - bitcount? |
|
/** |
|
* Left shifts the contents of one int array into another. |
|
* |
|
* @param src The source array. |
|
* @param idx The initial index of the source array. |
|
* @param result The destination array. |
|
* @param bitcount The left shift. |
|
* @param anticount The left anti-shift, e.g., <code>32-bitcount</code>. |
|
* @param prev The prior source value. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){ |
|
for (; idx > 0; idx--) { |
|
int v = (prev << bitcount); |
|
prev = src[idx - 1]; |
|
v |= (prev >>> anticount); |
|
result[idx] = v; |
|
} |
|
int v = prev << bitcount; |
|
result[0] = v; |
|
} |
|
|
|
/** |
|
* Shifts this <code>FDBigInteger</code> to the left. The shift is performed |
|
* in-place unless the <code>FDBigInteger</code> is immutable in which case |
|
* a new instance of <code>FDBigInteger</code> is returned. |
|
* |
|
* @param shift The number of bits to shift left. |
|
* @return The shifted <code>FDBigInteger</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger leftShift(int shift) { |
|
if (shift == 0 || nWords == 0) { |
|
return this; |
|
} |
|
int wordcount = shift >> 5; |
|
int bitcount = shift & 0x1f; |
|
if (this.isImmutable) { |
|
if (bitcount == 0) { |
|
return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount); |
|
} else { |
|
int anticount = 32 - bitcount; |
|
int idx = nWords - 1; |
|
int prev = data[idx]; |
|
int hi = prev >>> anticount; |
|
int[] result; |
|
if (hi != 0) { |
|
result = new int[nWords + 1]; |
|
result[nWords] = hi; |
|
} else { |
|
result = new int[nWords]; |
|
} |
|
leftShift(data,idx,result,bitcount,anticount,prev); |
|
return new FDBigInteger(result, offset + wordcount); |
|
} |
|
} else { |
|
if (bitcount != 0) { |
|
int anticount = 32 - bitcount; |
|
if ((data[0] << bitcount) == 0) { |
|
int idx = 0; |
|
int prev = data[idx]; |
|
for (; idx < nWords - 1; idx++) { |
|
int v = (prev >>> anticount); |
|
prev = data[idx + 1]; |
|
v |= (prev << bitcount); |
|
data[idx] = v; |
|
} |
|
int v = prev >>> anticount; |
|
data[idx] = v; |
|
if(v==0) { |
|
nWords--; |
|
} |
|
offset++; |
|
} else { |
|
int idx = nWords - 1; |
|
int prev = data[idx]; |
|
int hi = prev >>> anticount; |
|
int[] result = data; |
|
int[] src = data; |
|
if (hi != 0) { |
|
if(nWords == data.length) { |
|
data = result = new int[nWords + 1]; |
|
} |
|
result[nWords++] = hi; |
|
} |
|
leftShift(src,idx,result,bitcount,anticount,prev); |
|
} |
|
} |
|
offset += wordcount; |
|
return this; |
|
} |
|
} |
|
|
|
/** |
|
* Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents. |
|
* |
|
* @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private int size() { |
|
return nWords + offset; |
|
} |
|
|
|
|
|
/** |
|
* Computes |
|
* <pre> |
|
* q = (int)( this / S ) |
|
* this = 10 * ( this mod S ) |
|
* Return q. |
|
* </pre> |
|
* This is the iteration step of digit development for output. |
|
* We assume that S has been normalized, as above, and that |
|
* "this" has been left-shifted accordingly. |
|
* Also assumed, of course, is that the result, q, can be expressed |
|
* as an integer, {@code 0 <= q < 10}. |
|
* |
|
* @param S The divisor of this <code>FDBigInteger</code>. |
|
* @return <code>q = (int)(this / S)</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException { |
|
assert !this.isImmutable : "cannot modify immutable value"; |
|
// ensure that this and S have the same number of |
|
// digits. If S is properly normalized and q < 10 then |
|
|
|
int thSize = this.size(); |
|
int sSize = S.size(); |
|
if (thSize < sSize) { |
|
// this value is significantly less than S, result of division is zero. |
|
|
|
int p = multAndCarryBy10(this.data, this.nWords, this.data); |
|
if(p!=0) { |
|
this.data[nWords++] = p; |
|
} else { |
|
trimLeadingZeros(); |
|
} |
|
return 0; |
|
} else if (thSize > sSize) { |
|
throw new IllegalArgumentException("disparate values"); |
|
} |
|
// estimate q the obvious way. We will usually be |
|
// right. If not, then we're only off by a little and |
|
|
|
long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK); |
|
long diff = multDiffMe(q, S); |
|
if (diff != 0L) { |
|
//@ assert q != 0; |
|
//@ assert this.offset == \old(Math.min(this.offset, S.offset)); |
|
//@ assert this.offset <= S.offset; |
|
|
|
// q is too big. |
|
// add S back in until this turns +. This should |
|
|
|
long sum = 0L; |
|
int tStart = S.offset - this.offset; |
|
|
|
int[] sd = S.data; |
|
int[] td = this.data; |
|
while (sum == 0L) { |
|
for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) { |
|
sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK); |
|
td[tIndex] = (int) sum; |
|
sum >>>= 32; |
|
} |
|
// |
|
// Originally the following line read |
|
// "if ( sum !=0 && sum != -1 )" |
|
// but that would be wrong, because of the |
|
// treatment of the two values as entirely unsigned, |
|
// it would be impossible for a carry-out to be interpreted |
|
// as -1 -- it would have to be a single-bit carry-out, or +1. |
|
// |
|
assert sum == 0 || sum == 1 : sum; |
|
q -= 1; |
|
} |
|
} |
|
// finally, we can multiply this by 10. |
|
// it cannot overflow, right, as the high-order word has |
|
|
|
int p = multAndCarryBy10(this.data, this.nWords, this.data); |
|
assert p == 0 : p; |
|
trimLeadingZeros(); |
|
return (int) q; |
|
} |
|
|
|
/** |
|
* Multiplies this <code>FDBigInteger</code> by 10. The operation will be |
|
* performed in place unless the <code>FDBigInteger</code> is immutable in |
|
* which case a new <code>FDBigInteger</code> will be returned. |
|
* |
|
* @return The <code>FDBigInteger</code> multiplied by 10. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger multBy10() { |
|
if (nWords == 0) { |
|
return this; |
|
} |
|
if (isImmutable) { |
|
int[] res = new int[nWords + 1]; |
|
res[nWords] = multAndCarryBy10(data, nWords, res); |
|
return new FDBigInteger(res, offset); |
|
} else { |
|
int p = multAndCarryBy10(this.data, this.nWords, this.data); |
|
if (p != 0) { |
|
if (nWords == data.length) { |
|
if (data[0] == 0) { |
|
System.arraycopy(data, 1, data, 0, --nWords); |
|
offset++; |
|
} else { |
|
data = Arrays.copyOf(data, data.length + 1); |
|
} |
|
} |
|
data[nWords++] = p; |
|
} else { |
|
trimLeadingZeros(); |
|
} |
|
return this; |
|
} |
|
} |
|
|
|
/** |
|
* Multiplies this <code>FDBigInteger</code> by |
|
* <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be |
|
* performed in place if possible, otherwise a new <code>FDBigInteger</code> |
|
* will be returned. |
|
* |
|
* @param p5 The exponent of the power-of-five factor. |
|
* @param p2 The exponent of the power-of-two factor. |
|
* @return The multiplication result. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger multByPow52(int p5, int p2) { |
|
if (this.nWords == 0) { |
|
return this; |
|
} |
|
FDBigInteger res = this; |
|
if (p5 != 0) { |
|
int[] r; |
|
int extraSize = (p2 != 0) ? 1 : 0; |
|
if (p5 < SMALL_5_POW.length) { |
|
r = new int[this.nWords + 1 + extraSize]; |
|
mult(this.data, this.nWords, SMALL_5_POW[p5], r); |
|
res = new FDBigInteger(r, this.offset); |
|
} else { |
|
FDBigInteger pow5 = big5pow(p5); |
|
r = new int[this.nWords + pow5.size() + extraSize]; |
|
mult(this.data, this.nWords, pow5.data, pow5.nWords, r); |
|
res = new FDBigInteger(r, this.offset + pow5.offset); |
|
} |
|
} |
|
return res.leftShift(p2); |
|
} |
|
|
|
/** |
|
* Multiplies two big integers represented as int arrays. |
|
* |
|
* @param s1 The first array factor. |
|
* @param s1Len The number of elements of <code>s1</code> to use. |
|
* @param s2 The second array factor. |
|
* @param s2Len The number of elements of <code>s2</code> to use. |
|
* @param dst The product array. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) { |
|
for (int i = 0; i < s1Len; i++) { |
|
long v = s1[i] & LONG_MASK; |
|
long p = 0L; |
|
for (int j = 0; j < s2Len; j++) { |
|
p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK); |
|
dst[i + j] = (int) p; |
|
p >>>= 32; |
|
} |
|
dst[i + s2Len] = (int) p; |
|
} |
|
} |
|
|
|
/** |
|
* Subtracts the supplied <code>FDBigInteger</code> subtrahend from this |
|
* <code>FDBigInteger</code>. Assert that the result is positive. |
|
* If the subtrahend is immutable, store the result in this(minuend). |
|
* If this(minuend) is immutable a new <code>FDBigInteger</code> is created. |
|
* |
|
* @param subtrahend The <code>FDBigInteger</code> to be subtracted. |
|
* @return This <code>FDBigInteger</code> less the subtrahend. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) { |
|
assert this.size() >= subtrahend.size() : "result should be positive"; |
|
FDBigInteger minuend; |
|
if (this.isImmutable) { |
|
minuend = new FDBigInteger(this.data.clone(), this.offset); |
|
} else { |
|
minuend = this; |
|
} |
|
int offsetDiff = subtrahend.offset - minuend.offset; |
|
int[] sData = subtrahend.data; |
|
int[] mData = minuend.data; |
|
int subLen = subtrahend.nWords; |
|
int minLen = minuend.nWords; |
|
if (offsetDiff < 0) { |
|
|
|
int rLen = minLen - offsetDiff; |
|
if (rLen < mData.length) { |
|
System.arraycopy(mData, 0, mData, -offsetDiff, minLen); |
|
Arrays.fill(mData, 0, -offsetDiff, 0); |
|
} else { |
|
int[] r = new int[rLen]; |
|
System.arraycopy(mData, 0, r, -offsetDiff, minLen); |
|
minuend.data = mData = r; |
|
} |
|
minuend.offset = subtrahend.offset; |
|
minuend.nWords = minLen = rLen; |
|
offsetDiff = 0; |
|
} |
|
long borrow = 0L; |
|
int mIndex = offsetDiff; |
|
for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) { |
|
long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; |
|
mData[mIndex] = (int) diff; |
|
borrow = diff >> 32; |
|
} |
|
for (; borrow != 0 && mIndex < minLen; mIndex++) { |
|
long diff = (mData[mIndex] & LONG_MASK) + borrow; |
|
mData[mIndex] = (int) diff; |
|
borrow = diff >> 32; |
|
} |
|
assert borrow == 0L : borrow; |
|
|
|
minuend.trimLeadingZeros(); |
|
return minuend; |
|
} |
|
|
|
/** |
|
* Subtracts the supplied <code>FDBigInteger</code> subtrahend from this |
|
* <code>FDBigInteger</code>. Assert that the result is positive. |
|
* If the this(minuend) is immutable, store the result in subtrahend. |
|
* If subtrahend is immutable a new <code>FDBigInteger</code> is created. |
|
* |
|
* @param subtrahend The <code>FDBigInteger</code> to be subtracted. |
|
* @return This <code>FDBigInteger</code> less the subtrahend. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) { |
|
assert this.size() >= subtrahend.size() : "result should be positive"; |
|
FDBigInteger minuend = this; |
|
if (subtrahend.isImmutable) { |
|
subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset); |
|
} |
|
int offsetDiff = minuend.offset - subtrahend.offset; |
|
int[] sData = subtrahend.data; |
|
int[] mData = minuend.data; |
|
int subLen = subtrahend.nWords; |
|
int minLen = minuend.nWords; |
|
if (offsetDiff < 0) { |
|
int rLen = minLen; |
|
if (rLen < sData.length) { |
|
System.arraycopy(sData, 0, sData, -offsetDiff, subLen); |
|
Arrays.fill(sData, 0, -offsetDiff, 0); |
|
} else { |
|
int[] r = new int[rLen]; |
|
System.arraycopy(sData, 0, r, -offsetDiff, subLen); |
|
subtrahend.data = sData = r; |
|
} |
|
subtrahend.offset = minuend.offset; |
|
subLen -= offsetDiff; |
|
offsetDiff = 0; |
|
} else { |
|
int rLen = minLen + offsetDiff; |
|
if (rLen >= sData.length) { |
|
subtrahend.data = sData = Arrays.copyOf(sData, rLen); |
|
} |
|
} |
|
//@ assert minuend == this && minuend.value() == \old(this.value()); |
|
//@ assert mData == minuend.data && minLen == minuend.nWords; |
|
//@ assert subtrahend.offset + subtrahend.data.length >= minuend.size(); |
|
//@ assert sData == subtrahend.data; |
|
//@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value()); |
|
//@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset); |
|
//@ assert offsetDiff == minuend.offset - subtrahend.offset; |
|
|
|
int sIndex = 0; |
|
long borrow = 0L; |
|
for (; sIndex < offsetDiff; sIndex++) { |
|
long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow; |
|
sData[sIndex] = (int) diff; |
|
borrow = diff >> 32; |
|
} |
|
|
|
for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) { |
|
|
|
long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; |
|
sData[sIndex] = (int) diff; |
|
borrow = diff >> 32; |
|
} |
|
assert borrow == 0L : borrow; |
|
|
|
subtrahend.nWords = sIndex; |
|
subtrahend.trimLeadingZeros(); |
|
return subtrahend; |
|
|
|
} |
|
|
|
/** |
|
* Determines whether all elements of an array are zero for all indices less |
|
* than a given index. |
|
* |
|
* @param a The array to be examined. |
|
* @param from The index strictly below which elements are to be examined. |
|
* @return Zero if all elements in range are zero, 1 otherwise. |
|
*/ |
|
|
|
|
|
|
|
@*/ |
|
private static int checkZeroTail(int[] a, int from) { |
|
while (from > 0) { |
|
if (a[--from] != 0) { |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
/** |
|
* Compares the parameter with this <code>FDBigInteger</code>. Returns an |
|
* integer accordingly as: |
|
* <pre>{@code |
|
* > 0: this > other |
|
* 0: this == other |
|
* < 0: this < other |
|
* }</pre> |
|
* |
|
* @param other The <code>FDBigInteger</code> to compare. |
|
* @return A negative value, zero, or a positive value according to the |
|
* result of the comparison. |
|
*/ |
|
|
|
|
|
@*/ |
|
public int cmp(FDBigInteger other) { |
|
int aSize = nWords + offset; |
|
int bSize = other.nWords + other.offset; |
|
if (aSize > bSize) { |
|
return 1; |
|
} else if (aSize < bSize) { |
|
return -1; |
|
} |
|
int aLen = nWords; |
|
int bLen = other.nWords; |
|
while (aLen > 0 && bLen > 0) { |
|
int a = data[--aLen]; |
|
int b = other.data[--bLen]; |
|
if (a != b) { |
|
return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; |
|
} |
|
} |
|
if (aLen > 0) { |
|
return checkZeroTail(data, aLen); |
|
} |
|
if (bLen > 0) { |
|
return -checkZeroTail(other.data, bLen); |
|
} |
|
return 0; |
|
} |
|
|
|
/** |
|
* Compares this <code>FDBigInteger</code> with |
|
* <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. |
|
* Returns an integer accordingly as: |
|
* <pre>{@code |
|
* > 0: this > other |
|
* 0: this == other |
|
* < 0: this < other |
|
* }</pre> |
|
* @param p5 The exponent of the power-of-five factor. |
|
* @param p2 The exponent of the power-of-two factor. |
|
* @return A negative value, zero, or a positive value according to the |
|
* result of the comparison. |
|
*/ |
|
|
|
|
|
|
|
@*/ |
|
public int cmpPow52(int p5, int p2) { |
|
if (p5 == 0) { |
|
int wordcount = p2 >> 5; |
|
int bitcount = p2 & 0x1f; |
|
int size = this.nWords + this.offset; |
|
if (size > wordcount + 1) { |
|
return 1; |
|
} else if (size < wordcount + 1) { |
|
return -1; |
|
} |
|
int a = this.data[this.nWords -1]; |
|
int b = 1 << bitcount; |
|
if (a != b) { |
|
return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; |
|
} |
|
return checkZeroTail(this.data, this.nWords - 1); |
|
} |
|
return this.cmp(big5pow(p5).leftShift(p2)); |
|
} |
|
|
|
/** |
|
* Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a |
|
* value according to the comparison as: |
|
* <pre>{@code |
|
* -1: this < x + y |
|
* 0: this == x + y |
|
* 1: this > x + y |
|
* }</pre> |
|
* @param x The first addend of the sum to compare. |
|
* @param y The second addend of the sum to compare. |
|
* @return -1, 0, or 1 according to the result of the comparison. |
|
*/ |
|
|
|
|
|
@*/ |
|
public int addAndCmp(FDBigInteger x, FDBigInteger y) { |
|
FDBigInteger big; |
|
FDBigInteger small; |
|
int xSize = x.size(); |
|
int ySize = y.size(); |
|
int bSize; |
|
int sSize; |
|
if (xSize >= ySize) { |
|
big = x; |
|
small = y; |
|
bSize = xSize; |
|
sSize = ySize; |
|
} else { |
|
big = y; |
|
small = x; |
|
bSize = ySize; |
|
sSize = xSize; |
|
} |
|
int thSize = this.size(); |
|
if (bSize == 0) { |
|
return thSize == 0 ? 0 : 1; |
|
} |
|
if (sSize == 0) { |
|
return this.cmp(big); |
|
} |
|
if (bSize > thSize) { |
|
return -1; |
|
} |
|
if (bSize + 1 < thSize) { |
|
return 1; |
|
} |
|
long top = (big.data[big.nWords - 1] & LONG_MASK); |
|
if (sSize == bSize) { |
|
top += (small.data[small.nWords - 1] & LONG_MASK); |
|
} |
|
if ((top >>> 32) == 0) { |
|
if (((top + 1) >>> 32) == 0) { |
|
|
|
if (bSize < thSize) { |
|
return 1; |
|
} |
|
|
|
long v = (this.data[this.nWords - 1] & LONG_MASK); |
|
if (v < top) { |
|
return -1; |
|
} |
|
if (v > top + 1) { |
|
return 1; |
|
} |
|
} |
|
} else { |
|
if (bSize + 1 > thSize) { |
|
return -1; |
|
} |
|
|
|
top >>>= 32; |
|
long v = (this.data[this.nWords - 1] & LONG_MASK); |
|
if (v < top) { |
|
return -1; |
|
} |
|
if (v > top + 1) { |
|
return 1; |
|
} |
|
} |
|
return this.cmp(big.add(small)); |
|
} |
|
|
|
/** |
|
* Makes this <code>FDBigInteger</code> immutable. |
|
*/ |
|
|
|
|
|
|
|
@*/ |
|
public void makeImmutable() { |
|
this.isImmutable = true; |
|
} |
|
|
|
/** |
|
* Multiplies this <code>FDBigInteger</code> by an integer. |
|
* |
|
* @param i The factor by which to multiply this <code>FDBigInteger</code>. |
|
* @return This <code>FDBigInteger</code> multiplied by an integer. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private FDBigInteger mult(int i) { |
|
if (this.nWords == 0) { |
|
return this; |
|
} |
|
int[] r = new int[nWords + 1]; |
|
mult(data, nWords, i, r); |
|
return new FDBigInteger(r, offset); |
|
} |
|
|
|
/** |
|
* Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>. |
|
* |
|
* @param other The <code>FDBigInteger</code> factor by which to multiply. |
|
* @return The product of this and the parameter <code>FDBigInteger</code>s. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private FDBigInteger mult(FDBigInteger other) { |
|
if (this.nWords == 0) { |
|
return this; |
|
} |
|
if (this.size() == 1) { |
|
return other.mult(data[0]); |
|
} |
|
if (other.nWords == 0) { |
|
return other; |
|
} |
|
if (other.size() == 1) { |
|
return this.mult(other.data[0]); |
|
} |
|
int[] r = new int[nWords + other.nWords]; |
|
mult(this.data, this.nWords, other.data, other.nWords, r); |
|
return new FDBigInteger(r, this.offset + other.offset); |
|
} |
|
|
|
/** |
|
* Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>. |
|
* |
|
* @param other The <code>FDBigInteger</code> to add. |
|
* @return The sum of the <code>FDBigInteger</code>s. |
|
*/ |
|
|
|
|
|
|
|
@*/ |
|
private FDBigInteger add(FDBigInteger other) { |
|
FDBigInteger big, small; |
|
int bigLen, smallLen; |
|
int tSize = this.size(); |
|
int oSize = other.size(); |
|
if (tSize >= oSize) { |
|
big = this; |
|
bigLen = tSize; |
|
small = other; |
|
smallLen = oSize; |
|
} else { |
|
big = other; |
|
bigLen = oSize; |
|
small = this; |
|
smallLen = tSize; |
|
} |
|
int[] r = new int[bigLen + 1]; |
|
int i = 0; |
|
long carry = 0L; |
|
for (; i < smallLen; i++) { |
|
carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ) |
|
+ ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK))); |
|
r[i] = (int) carry; |
|
carry >>= 32; |
|
} |
|
for (; i < bigLen; i++) { |
|
carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ); |
|
r[i] = (int) carry; |
|
carry >>= 32; |
|
} |
|
r[bigLen] = (int) carry; |
|
return new FDBigInteger(r, 0); |
|
} |
|
|
|
|
|
/** |
|
* Multiplies a <code>FDBigInteger</code> by an int and adds another int. The |
|
* result is computed in place. This method is intended only to be invoked |
|
* from |
|
* <code> |
|
* FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) |
|
* </code>. |
|
* |
|
* @param iv The factor by which to multiply this <code>FDBigInteger</code>. |
|
* @param addend The value to add to the product of this |
|
* <code>FDBigInteger</code> and <code>iv</code>. |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
private void multAddMe(int iv, int addend) { |
|
long v = iv & LONG_MASK; |
|
|
|
long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK); |
|
data[0] = (int) p; |
|
p >>>= 32; |
|
for (int i = 1; i < nWords; i++) { |
|
p += v * (data[i] & LONG_MASK); |
|
data[i] = (int) p; |
|
p >>>= 32; |
|
} |
|
if (p != 0L) { |
|
data[nWords++] = (int) p; |
|
} |
|
} |
|
|
|
// |
|
// original doc: |
|
// |
|
// do this -=q*S |
|
// returns borrow |
|
// |
|
/** |
|
* Multiplies the parameters and subtracts them from this |
|
* <code>FDBigInteger</code>. |
|
* |
|
* @param q The integer parameter. |
|
* @param S The <code>FDBigInteger</code> parameter. |
|
* @return <code>this - q*S</code>. |
|
*/ |
|
/*@ |
|
@ ensures nWords == 0 ==> offset == 0; |
|
@ ensures nWords > 0 ==> data[nWords - 1] != 0; |
|
@*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private long multDiffMe(long q, FDBigInteger S) { |
|
long diff = 0L; |
|
if (q != 0) { |
|
int deltaSize = S.offset - this.offset; |
|
if (deltaSize >= 0) { |
|
int[] sd = S.data; |
|
int[] td = this.data; |
|
for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) { |
|
diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); |
|
td[tIndex] = (int) diff; |
|
diff >>= 32; |
|
} |
|
} else { |
|
deltaSize = -deltaSize; |
|
int[] rd = new int[nWords + deltaSize]; |
|
int sIndex = 0; |
|
int rIndex = 0; |
|
int[] sd = S.data; |
|
for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) { |
|
diff -= q * (sd[sIndex] & LONG_MASK); |
|
rd[rIndex] = (int) diff; |
|
diff >>= 32; |
|
} |
|
int tIndex = 0; |
|
int[] td = this.data; |
|
for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) { |
|
diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); |
|
rd[rIndex] = (int) diff; |
|
diff >>= 32; |
|
} |
|
this.nWords += deltaSize; |
|
this.offset -= deltaSize; |
|
this.data = rd; |
|
} |
|
} |
|
return diff; |
|
} |
|
|
|
|
|
/** |
|
* Multiplies by 10 a big integer represented as an array. The final carry |
|
* is returned. |
|
* |
|
* @param src The array representation of the big integer. |
|
* @param srcLen The number of elements of <code>src</code> to use. |
|
* @param dst The product array. |
|
* @return The final carry of the multiplication. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) { |
|
long carry = 0; |
|
for (int i = 0; i < srcLen; i++) { |
|
long product = (src[i] & LONG_MASK) * 10L + carry; |
|
dst[i] = (int) product; |
|
carry = product >>> 32; |
|
} |
|
return (int) carry; |
|
} |
|
|
|
/** |
|
* Multiplies by a constant value a big integer represented as an array. |
|
* The constant factor is an <code>int</code>. |
|
* |
|
* @param src The array representation of the big integer. |
|
* @param srcLen The number of elements of <code>src</code> to use. |
|
* @param value The constant factor by which to multiply. |
|
* @param dst The product array. |
|
*/ |
|
|
|
|
|
|
|
|
|
@*/ |
|
private static void mult(int[] src, int srcLen, int value, int[] dst) { |
|
long val = value & LONG_MASK; |
|
long carry = 0; |
|
for (int i = 0; i < srcLen; i++) { |
|
long product = (src[i] & LONG_MASK) * val + carry; |
|
dst[i] = (int) product; |
|
carry = product >>> 32; |
|
} |
|
dst[srcLen] = (int) carry; |
|
} |
|
|
|
/** |
|
* Multiplies by a constant value a big integer represented as an array. |
|
* The constant factor is a long represent as two <code>int</code>s. |
|
* |
|
* @param src The array representation of the big integer. |
|
* @param srcLen The number of elements of <code>src</code> to use. |
|
* @param v0 The lower 32 bits of the long factor. |
|
* @param v1 The upper 32 bits of the long factor. |
|
* @param dst The product array. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@*/ |
|
private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) { |
|
long v = v0 & LONG_MASK; |
|
long carry = 0; |
|
for (int j = 0; j < srcLen; j++) { |
|
long product = v * (src[j] & LONG_MASK) + carry; |
|
dst[j] = (int) product; |
|
carry = product >>> 32; |
|
} |
|
dst[srcLen] = (int) carry; |
|
v = v1 & LONG_MASK; |
|
carry = 0; |
|
for (int j = 0; j < srcLen; j++) { |
|
long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry; |
|
dst[j + 1] = (int) product; |
|
carry = product >>> 32; |
|
} |
|
dst[srcLen + 1] = (int) carry; |
|
} |
|
|
|
// Fails assertion for negative exponent. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static FDBigInteger big5pow(int p) { |
|
assert p >= 0 : p; |
|
if (p < MAX_FIVE_POW) { |
|
return POW_5_CACHE[p]; |
|
} |
|
return big5powRec(p); |
|
} |
|
|
|
// slow path |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static FDBigInteger big5powRec(int p) { |
|
if (p < MAX_FIVE_POW) { |
|
return POW_5_CACHE[p]; |
|
} |
|
// construct the value. |
|
|
|
int q, r; |
|
// in order to compute 5^p, |
|
// compute its square root, 5^(p/2) and square. |
|
// or, let q = p / 2, r = p -q, then |
|
|
|
q = p >> 1; |
|
r = p - q; |
|
FDBigInteger bigq = big5powRec(q); |
|
if (r < SMALL_5_POW.length) { |
|
return bigq.mult(SMALL_5_POW[r]); |
|
} else { |
|
return bigq.mult(big5powRec(r)); |
|
} |
|
} |
|
|
|
// for debugging ... |
|
|
|
|
|
|
|
|
|
*/ |
|
public String toHexString(){ |
|
if(nWords ==0) { |
|
return "0"; |
|
} |
|
StringBuilder sb = new StringBuilder((nWords +offset)*8); |
|
for(int i= nWords -1; i>=0; i--) { |
|
String subStr = Integer.toHexString(data[i]); |
|
for(int j = subStr.length(); j<8; j++) { |
|
sb.append('0'); |
|
} |
|
sb.append(subStr); |
|
} |
|
for(int i=offset; i>0; i--) { |
|
sb.append("00000000"); |
|
} |
|
return sb.toString(); |
|
} |
|
|
|
// for debugging ... |
|
|
|
|
|
|
|
|
|
*/ |
|
public BigInteger toBigInteger() { |
|
byte[] magnitude = new byte[nWords * 4 + 1]; |
|
for (int i = 0; i < nWords; i++) { |
|
int w = data[i]; |
|
magnitude[magnitude.length - 4 * i - 1] = (byte) w; |
|
magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8); |
|
magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16); |
|
magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24); |
|
} |
|
return new BigInteger(magnitude).shiftLeft(offset * 32); |
|
} |
|
|
|
// for debugging ... |
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public String toString(){ |
|
return toBigInteger().toString(); |
|
} |
|
} |