mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-22 08:21:27 +00:00
7082971: More performance tuning of BigDecimal and other java.math classes
Reviewed-by: darcy
This commit is contained in:
parent
bfeee8da4d
commit
238bb5d3bb
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -353,27 +353,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
mag = trustedStripLeadingZeroInts(magnitude);
|
||||
}
|
||||
|
||||
// Constructs a new BigInteger using a char array with radix=10
|
||||
BigInteger(char[] val) {
|
||||
/*
|
||||
* Constructs a new BigInteger using a char array with radix=10.
|
||||
* Sign is precalculated outside and not allowed in the val.
|
||||
*/
|
||||
BigInteger(char[] val, int sign, int len) {
|
||||
int cursor = 0, numDigits;
|
||||
int len = val.length;
|
||||
|
||||
// Check for leading minus sign
|
||||
int sign = 1;
|
||||
if (val[0] == '-') {
|
||||
if (len == 1)
|
||||
throw new NumberFormatException("Zero length BigInteger");
|
||||
sign = -1;
|
||||
cursor = 1;
|
||||
} else if (val[0] == '+') {
|
||||
if (len == 1)
|
||||
throw new NumberFormatException("Zero length BigInteger");
|
||||
cursor = 1;
|
||||
}
|
||||
|
||||
// Skip leading zeros and compute number of digits in magnitude
|
||||
while (cursor < len && Character.digit(val[cursor], 10) == 0)
|
||||
while (cursor < len && Character.digit(val[cursor], 10) == 0) {
|
||||
cursor++;
|
||||
}
|
||||
if (cursor == len) {
|
||||
signum = 0;
|
||||
mag = ZERO.mag;
|
||||
@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
|
||||
numDigits = len - cursor;
|
||||
signum = sign;
|
||||
|
||||
// Pre-allocate array of expected size
|
||||
int numWords;
|
||||
if (len < 10) {
|
||||
@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return new BigInteger(resultMag, cmp == signum ? 1 : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private methods used by BigDecimal code to add a BigInteger
|
||||
* with a long. Assumes val is not equal to INFLATED.
|
||||
*/
|
||||
BigInteger add(long val) {
|
||||
if (val == 0)
|
||||
return this;
|
||||
if (signum == 0)
|
||||
return valueOf(val);
|
||||
if (Long.signum(val) == signum)
|
||||
return new BigInteger(add(mag, Math.abs(val)), signum);
|
||||
int cmp = compareMagnitude(val);
|
||||
if (cmp == 0)
|
||||
return ZERO;
|
||||
int[] resultMag = (cmp > 0 ? subtract(mag, Math.abs(val)) : subtract(Math.abs(val), mag));
|
||||
resultMag = trustedStripLeadingZeroInts(resultMag);
|
||||
return new BigInteger(resultMag, cmp == signum ? 1 : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the contents of the int array x and long value val. This
|
||||
* method allocates a new int array to hold the answer and returns
|
||||
* a reference to that array. Assumes x.length > 0 and val is
|
||||
* non-negative
|
||||
*/
|
||||
private static int[] add(int[] x, long val) {
|
||||
int[] y;
|
||||
long sum = 0;
|
||||
int xIndex = x.length;
|
||||
int[] result;
|
||||
int highWord = (int)(val >>> 32);
|
||||
if (highWord==0) {
|
||||
result = new int[xIndex];
|
||||
sum = (x[--xIndex] & LONG_MASK) + val;
|
||||
result[xIndex] = (int)sum;
|
||||
} else {
|
||||
if (xIndex == 1) {
|
||||
result = new int[2];
|
||||
sum = val + (x[0] & LONG_MASK);
|
||||
result[1] = (int)sum;
|
||||
result[0] = (int)(sum >>> 32);
|
||||
return result;
|
||||
} else {
|
||||
result = new int[xIndex];
|
||||
sum = (x[--xIndex] & LONG_MASK) + (val & LONG_MASK);
|
||||
result[xIndex] = (int)sum;
|
||||
sum = (x[--xIndex] & LONG_MASK) + (highWord & LONG_MASK) + (sum >>> 32);
|
||||
result[xIndex] = (int)sum;
|
||||
}
|
||||
}
|
||||
// Copy remainder of longer number while carry propagation is required
|
||||
boolean carry = (sum >>> 32 != 0);
|
||||
while (xIndex > 0 && carry)
|
||||
carry = ((result[--xIndex] = x[xIndex] + 1) == 0);
|
||||
// Copy remainder of longer number
|
||||
while (xIndex > 0)
|
||||
result[--xIndex] = x[xIndex];
|
||||
// Grow result if necessary
|
||||
if (carry) {
|
||||
int bigger[] = new int[result.length + 1];
|
||||
System.arraycopy(result, 0, bigger, 1, result.length);
|
||||
bigger[0] = 0x01;
|
||||
return bigger;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the contents of the int arrays x and y. This method allocates
|
||||
* a new int array to hold the answer and returns a reference to that
|
||||
@ -1074,14 +1130,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
int yIndex = y.length;
|
||||
int result[] = new int[xIndex];
|
||||
long sum = 0;
|
||||
|
||||
// Add common parts of both numbers
|
||||
while(yIndex > 0) {
|
||||
sum = (x[--xIndex] & LONG_MASK) +
|
||||
(y[--yIndex] & LONG_MASK) + (sum >>> 32);
|
||||
if(yIndex==1) {
|
||||
sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ;
|
||||
result[xIndex] = (int)sum;
|
||||
} else {
|
||||
// Add common parts of both numbers
|
||||
while(yIndex > 0) {
|
||||
sum = (x[--xIndex] & LONG_MASK) +
|
||||
(y[--yIndex] & LONG_MASK) + (sum >>> 32);
|
||||
result[xIndex] = (int)sum;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy remainder of longer number while carry propagation is required
|
||||
boolean carry = (sum >>> 32 != 0);
|
||||
while (xIndex > 0 && carry)
|
||||
@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int[] subtract(long val, int[] little) {
|
||||
int highWord = (int)(val >>> 32);
|
||||
if (highWord==0) {
|
||||
int result[] = new int[1];
|
||||
result[0] = (int)(val - (little[0] & LONG_MASK));
|
||||
return result;
|
||||
} else {
|
||||
int result[] = new int[2];
|
||||
if(little.length==1) {
|
||||
long difference = ((int)val & LONG_MASK) - (little[0] & LONG_MASK);
|
||||
result[1] = (int)difference;
|
||||
// Subtract remainder of longer number while borrow propagates
|
||||
boolean borrow = (difference >> 32 != 0);
|
||||
if(borrow) {
|
||||
result[0] = highWord - 1;
|
||||
} else { // Copy remainder of longer number
|
||||
result[0] = highWord;
|
||||
}
|
||||
return result;
|
||||
} else { // little.length==2
|
||||
long difference = ((int)val & LONG_MASK) - (little[1] & LONG_MASK);
|
||||
result[1] = (int)difference;
|
||||
difference = (highWord & LONG_MASK) - (little[0] & LONG_MASK) + (difference >> 32);
|
||||
result[0] = (int)difference;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the contents of the second argument (val) from the
|
||||
* first (big). The first int array (big) must represent a larger number
|
||||
* than the second. This method allocates the space necessary to hold the
|
||||
* answer.
|
||||
* assumes val >= 0
|
||||
*/
|
||||
private static int[] subtract(int[] big, long val) {
|
||||
int highWord = (int)(val >>> 32);
|
||||
int bigIndex = big.length;
|
||||
int result[] = new int[bigIndex];
|
||||
long difference = 0;
|
||||
|
||||
if (highWord==0) {
|
||||
difference = (big[--bigIndex] & LONG_MASK) - val;
|
||||
result[bigIndex] = (int)difference;
|
||||
} else {
|
||||
difference = (big[--bigIndex] & LONG_MASK) - (val & LONG_MASK);
|
||||
result[bigIndex] = (int)difference;
|
||||
difference = (big[--bigIndex] & LONG_MASK) - (highWord & LONG_MASK) + (difference >> 32);
|
||||
result[bigIndex] = (int)difference;
|
||||
}
|
||||
|
||||
|
||||
// Subtract remainder of longer number while borrow propagates
|
||||
boolean borrow = (difference >> 32 != 0);
|
||||
while (bigIndex > 0 && borrow)
|
||||
borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
|
||||
|
||||
// Copy remainder of longer number
|
||||
while (bigIndex > 0)
|
||||
result[--bigIndex] = big[bigIndex];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BigInteger whose value is {@code (this - val)}.
|
||||
*
|
||||
@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
public BigInteger multiply(BigInteger val) {
|
||||
if (val.signum == 0 || signum == 0)
|
||||
return ZERO;
|
||||
|
||||
int resultSign = signum == val.signum ? 1 : -1;
|
||||
if (val.mag.length == 1) {
|
||||
return multiplyByInt(mag,val.mag[0], resultSign);
|
||||
}
|
||||
if(mag.length == 1) {
|
||||
return multiplyByInt(val.mag,mag[0], resultSign);
|
||||
}
|
||||
int[] result = multiplyToLen(mag, mag.length,
|
||||
val.mag, val.mag.length, null);
|
||||
result = trustedStripLeadingZeroInts(result);
|
||||
return new BigInteger(result, signum == val.signum ? 1 : -1);
|
||||
return new BigInteger(result, resultSign);
|
||||
}
|
||||
|
||||
private static BigInteger multiplyByInt(int[] x, int y, int sign) {
|
||||
if(Integer.bitCount(y)==1) {
|
||||
return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign);
|
||||
}
|
||||
int xlen = x.length;
|
||||
int[] rmag = new int[xlen + 1];
|
||||
long carry = 0;
|
||||
long yl = y & LONG_MASK;
|
||||
int rstart = rmag.length - 1;
|
||||
for (int i = xlen - 1; i >= 0; i--) {
|
||||
long product = (x[i] & LONG_MASK) * yl + carry;
|
||||
rmag[rstart--] = (int)product;
|
||||
carry = product >>> 32;
|
||||
}
|
||||
if (carry == 0L) {
|
||||
rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
|
||||
} else {
|
||||
rmag[rstart] = (int)carry;
|
||||
}
|
||||
return new BigInteger(rmag, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1339,8 +1491,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
a = new MutableBigInteger(this.mag),
|
||||
b = new MutableBigInteger(val.mag);
|
||||
|
||||
a.divide(b, q);
|
||||
return q.toBigInteger(this.signum == val.signum ? 1 : -1);
|
||||
a.divide(b, q, false);
|
||||
return q.toBigInteger(this.signum * val.signum);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return shiftRight(-n);
|
||||
}
|
||||
}
|
||||
int[] newMag = shiftLeft(mag,n);
|
||||
|
||||
return new BigInteger(newMag, signum);
|
||||
}
|
||||
|
||||
private static int[] shiftLeft(int[] mag, int n) {
|
||||
int nInts = n >>> 5;
|
||||
int nBits = n & 0x1f;
|
||||
int magLen = mag.length;
|
||||
@ -2094,8 +2251,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2;
|
||||
newMag[i] = mag[j] << nBits;
|
||||
}
|
||||
|
||||
return new BigInteger(newMag, signum);
|
||||
return newMag;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of compareMagnitude that compares magnitude with long value.
|
||||
* val can't be Long.MIN_VALUE.
|
||||
*/
|
||||
final int compareMagnitude(long val) {
|
||||
assert val != Long.MIN_VALUE;
|
||||
int[] m1 = mag;
|
||||
int len = m1.length;
|
||||
if(len > 2) {
|
||||
return 1;
|
||||
}
|
||||
if (val < 0) {
|
||||
val = -val;
|
||||
}
|
||||
int highWord = (int)(val >>> 32);
|
||||
if (highWord==0) {
|
||||
if (len < 1)
|
||||
return -1;
|
||||
if (len > 1)
|
||||
return 1;
|
||||
int a = m1[0];
|
||||
int b = (int)val;
|
||||
if (a != b) {
|
||||
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
int a = m1[0];
|
||||
int b = highWord;
|
||||
if (a != b) {
|
||||
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
|
||||
}
|
||||
a = m1[1];
|
||||
b = (int)val;
|
||||
if (a != b) {
|
||||
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this BigInteger with the specified Object for equality.
|
||||
*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -160,7 +160,7 @@ class MutableBigInteger {
|
||||
*/
|
||||
BigDecimal toBigDecimal(int sign, int scale) {
|
||||
if (intLen == 0 || sign == 0)
|
||||
return BigDecimal.valueOf(0, scale);
|
||||
return BigDecimal.zeroValueOf(scale);
|
||||
int[] mag = getMagnitudeArray();
|
||||
int len = mag.length;
|
||||
int d = mag[0];
|
||||
@ -171,7 +171,28 @@ class MutableBigInteger {
|
||||
long v = (len == 2) ?
|
||||
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
|
||||
d & LONG_MASK;
|
||||
return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
|
||||
return BigDecimal.valueOf(sign == -1 ? -v : v, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is for internal use in converting from a MutableBigInteger
|
||||
* object into a long value given a specified sign.
|
||||
* returns INFLATED if value is not fit into long
|
||||
*/
|
||||
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
|
||||
// make a BigInteger object for the resultant BigDecimal object.
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -543,6 +564,24 @@ class MutableBigInteger {
|
||||
return (int)carry;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method is the same as mulsun, except the fact that q array is not
|
||||
* updated, the only result of the method is borrow flag.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right shift this MutableBigInteger n bits, where n is
|
||||
* less than 32.
|
||||
@ -842,20 +881,20 @@ class MutableBigInteger {
|
||||
rem = (int) (remLong - (quotient.value[0] * divisorLong));
|
||||
remLong = rem & LONG_MASK;
|
||||
}
|
||||
|
||||
int xlen = intLen;
|
||||
int[] qWord = new int[2];
|
||||
while (--xlen > 0) {
|
||||
long dividendEstimate = (remLong<<32) |
|
||||
(value[offset + intLen - xlen] & LONG_MASK);
|
||||
long dividendEstimate = (remLong << 32) |
|
||||
(value[offset + intLen - xlen] & LONG_MASK);
|
||||
int q;
|
||||
if (dividendEstimate >= 0) {
|
||||
qWord[0] = (int) (dividendEstimate / divisorLong);
|
||||
qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
|
||||
q = (int) (dividendEstimate / divisorLong);
|
||||
rem = (int) (dividendEstimate - q * divisorLong);
|
||||
} else {
|
||||
divWord(qWord, dividendEstimate, divisor);
|
||||
long tmp = divWord(dividendEstimate, divisor);
|
||||
q = (int) (tmp & LONG_MASK);
|
||||
rem = (int) (tmp >>> 32);
|
||||
}
|
||||
quotient.value[intLen - xlen] = qWord[0];
|
||||
rem = qWord[1];
|
||||
quotient.value[intLen - xlen] = q;
|
||||
remLong = rem & LONG_MASK;
|
||||
}
|
||||
|
||||
@ -879,40 +918,45 @@ class MutableBigInteger {
|
||||
*
|
||||
*/
|
||||
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
|
||||
return divide(b,quotient,true);
|
||||
}
|
||||
|
||||
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) {
|
||||
if (b.intLen == 0)
|
||||
throw new ArithmeticException("BigInteger divide by zero");
|
||||
|
||||
// Dividend is zero
|
||||
if (intLen == 0) {
|
||||
quotient.intLen = quotient.offset;
|
||||
return new MutableBigInteger();
|
||||
return needReminder ? new MutableBigInteger() : null;
|
||||
}
|
||||
|
||||
int cmp = compare(b);
|
||||
// Dividend less than divisor
|
||||
if (cmp < 0) {
|
||||
quotient.intLen = quotient.offset = 0;
|
||||
return new MutableBigInteger(this);
|
||||
return needReminder ? new MutableBigInteger(this) : null;
|
||||
}
|
||||
// Dividend equal to divisor
|
||||
if (cmp == 0) {
|
||||
quotient.value[0] = quotient.intLen = 1;
|
||||
quotient.offset = 0;
|
||||
return new MutableBigInteger();
|
||||
return needReminder ? new MutableBigInteger() : null;
|
||||
}
|
||||
|
||||
quotient.clear();
|
||||
// Special case one word divisor
|
||||
if (b.intLen == 1) {
|
||||
int r = divideOneWord(b.value[b.offset], quotient);
|
||||
if (r == 0)
|
||||
return new MutableBigInteger();
|
||||
return new MutableBigInteger(r);
|
||||
if(needReminder) {
|
||||
if (r == 0)
|
||||
return new MutableBigInteger();
|
||||
return new MutableBigInteger(r);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy divisor value to protect divisor
|
||||
int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
|
||||
return divideMagnitude(div, quotient);
|
||||
return divideMagnitude(b, quotient, needReminder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -940,30 +984,72 @@ class MutableBigInteger {
|
||||
if (d == 0)
|
||||
return divideOneWord((int)v, quotient) & LONG_MASK;
|
||||
else {
|
||||
int[] div = new int[]{ d, (int)(v & LONG_MASK) };
|
||||
return divideMagnitude(div, quotient).toLong();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide this MutableBigInteger by the divisor represented by its magnitude
|
||||
* array. The quotient will be placed into the provided quotient object &
|
||||
* Divide this MutableBigInteger by the divisor.
|
||||
* The quotient will be placed into the provided quotient object &
|
||||
* the remainder object is returned.
|
||||
*/
|
||||
private MutableBigInteger divideMagnitude(int[] divisor,
|
||||
MutableBigInteger quotient) {
|
||||
|
||||
// Remainder starts as dividend with space for a leading zero
|
||||
MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
|
||||
System.arraycopy(value, offset, rem.value, 1, intLen);
|
||||
rem.intLen = intLen;
|
||||
rem.offset = 1;
|
||||
private MutableBigInteger divideMagnitude(MutableBigInteger div,
|
||||
MutableBigInteger quotient,
|
||||
boolean needReminder ) {
|
||||
// assert div.intLen > 1
|
||||
// D1 normalize the divisor
|
||||
int shift = Integer.numberOfLeadingZeros(div.value[div.offset]);
|
||||
// Copy divisor value to protect divisor
|
||||
final int dlen = div.intLen;
|
||||
int[] divisor;
|
||||
MutableBigInteger rem; // Remainder starts as dividend with space for a leading zero
|
||||
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;
|
||||
|
||||
// Set the quotient size
|
||||
int dlen = divisor.length;
|
||||
int limit = nlen - dlen + 1;
|
||||
final int limit = nlen - dlen + 1;
|
||||
if (quotient.value.length < limit) {
|
||||
quotient.value = new int[limit];
|
||||
quotient.offset = 0;
|
||||
@ -971,14 +1057,6 @@ class MutableBigInteger {
|
||||
quotient.intLen = limit;
|
||||
int[] q = quotient.value;
|
||||
|
||||
// D1 normalize the divisor
|
||||
int shift = Integer.numberOfLeadingZeros(divisor[0]);
|
||||
if (shift > 0) {
|
||||
// First shift will not grow array
|
||||
BigInteger.primitiveLeftShift(divisor, dlen, shift);
|
||||
// But this one might
|
||||
rem.leftShift(shift);
|
||||
}
|
||||
|
||||
// Must insert leading 0 in rem if its length did not change
|
||||
if (rem.intLen == nlen) {
|
||||
@ -990,10 +1068,9 @@ class MutableBigInteger {
|
||||
int dh = divisor[0];
|
||||
long dhLong = dh & LONG_MASK;
|
||||
int dl = divisor[1];
|
||||
int[] qWord = new int[2];
|
||||
|
||||
// D2 Initialize j
|
||||
for(int j=0; j<limit; j++) {
|
||||
for(int j=0; j<limit-1; j++) {
|
||||
// D3 Calculate qhat
|
||||
// estimate qhat
|
||||
int qhat = 0;
|
||||
@ -1013,9 +1090,9 @@ class MutableBigInteger {
|
||||
qhat = (int) (nChunk / dhLong);
|
||||
qrem = (int) (nChunk - (qhat * dhLong));
|
||||
} else {
|
||||
divWord(qWord, nChunk, dh);
|
||||
qhat = qWord[0];
|
||||
qrem = qWord[1];
|
||||
long tmp = divWord(nChunk, dh);
|
||||
qhat = (int) (tmp & LONG_MASK);
|
||||
qrem = (int) (tmp >>> 32);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1053,6 +1130,181 @@ class MutableBigInteger {
|
||||
// Store the quotient digit
|
||||
q[j] = qhat;
|
||||
} // D7 loop on j
|
||||
// D3 Calculate qhat
|
||||
// estimate 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) { // Correct qhat
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// D4 Multiply and subtract
|
||||
int borrow;
|
||||
rem.value[limit - 1 + rem.offset] = 0;
|
||||
if(needReminder)
|
||||
borrow = mulsub(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
|
||||
else
|
||||
borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
|
||||
|
||||
// D5 Test remainder
|
||||
if (borrow + 0x80000000 > nh2) {
|
||||
// D6 Add back
|
||||
if(needReminder)
|
||||
divadd(divisor, rem.value, limit - 1 + 1 + rem.offset);
|
||||
qhat--;
|
||||
}
|
||||
|
||||
// Store the quotient digit
|
||||
q[(limit - 1)] = qhat;
|
||||
}
|
||||
|
||||
|
||||
if(needReminder) {
|
||||
// D8 Unnormalize
|
||||
if (shift > 0)
|
||||
rem.rightShift(shift);
|
||||
rem.normalize();
|
||||
}
|
||||
quotient.normalize();
|
||||
return needReminder ? rem : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide this MutableBigInteger by the divisor represented by positive long
|
||||
* value. The quotient will be placed into the provided quotient object &
|
||||
* the remainder object is returned.
|
||||
*/
|
||||
private MutableBigInteger divideLongMagnitude(long ldivisor, MutableBigInteger quotient) {
|
||||
// Remainder starts as dividend with space for a leading zero
|
||||
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;
|
||||
|
||||
// D1 normalize the divisor
|
||||
int shift = Long.numberOfLeadingZeros(ldivisor);
|
||||
if (shift > 0) {
|
||||
ldivisor<<=shift;
|
||||
rem.leftShift(shift);
|
||||
}
|
||||
|
||||
// Must insert leading 0 in rem if its length did not change
|
||||
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);
|
||||
|
||||
// D2 Initialize j
|
||||
for (int j = 0; j < limit; j++) {
|
||||
// D3 Calculate qhat
|
||||
// estimate 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) { // Correct qhat
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// D4 Multiply and subtract
|
||||
rem.value[j + rem.offset] = 0;
|
||||
int borrow = mulsubLong(rem.value, dh, dl, qhat, j + rem.offset);
|
||||
|
||||
// D5 Test remainder
|
||||
if (borrow + 0x80000000 > nh2) {
|
||||
// D6 Add back
|
||||
divaddLong(dh,dl, rem.value, j + 1 + rem.offset);
|
||||
qhat--;
|
||||
}
|
||||
|
||||
// Store the quotient digit
|
||||
q[j] = qhat;
|
||||
} // D7 loop on j
|
||||
|
||||
// D8 Unnormalize
|
||||
if (shift > 0)
|
||||
@ -1063,6 +1315,46 @@ class MutableBigInteger {
|
||||
return rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* A primitive used for division by long.
|
||||
* Specialized version of the method divadd.
|
||||
* dh is a high part of the divisor, dl is a low part
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used for division by long.
|
||||
* Specialized version of the method sulsub.
|
||||
* dh is a high part of the divisor, dl is a low part
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two longs as if they were unsigned.
|
||||
* Returns true iff one is bigger than two.
|
||||
@ -1075,19 +1367,22 @@ class MutableBigInteger {
|
||||
* This method divides a long quantity by an int to estimate
|
||||
* qhat for two multi precision numbers. It is used when
|
||||
* the signed value of n is less than zero.
|
||||
* Returns long value where high 32 bits contain reminder value and
|
||||
* low 32 bits contain quotient value.
|
||||
*/
|
||||
private void divWord(int[] result, long n, int d) {
|
||||
static long divWord(long n, int d) {
|
||||
long dLong = d & LONG_MASK;
|
||||
|
||||
long r;
|
||||
long q;
|
||||
if (dLong == 1) {
|
||||
result[0] = (int)n;
|
||||
result[1] = 0;
|
||||
return;
|
||||
q = (int)n;
|
||||
r = 0;
|
||||
return (r << 32) | (q & LONG_MASK);
|
||||
}
|
||||
|
||||
// Approximate the quotient and remainder
|
||||
long q = (n >>> 1) / (dLong >>> 1);
|
||||
long r = n - q*dLong;
|
||||
q = (n >>> 1) / (dLong >>> 1);
|
||||
r = n - q*dLong;
|
||||
|
||||
// Correct the approximation
|
||||
while (r < 0) {
|
||||
@ -1098,10 +1393,8 @@ class MutableBigInteger {
|
||||
r -= dLong;
|
||||
q++;
|
||||
}
|
||||
|
||||
// n - q*dlong == r && 0 <= r <dLong, hence we're done.
|
||||
result[0] = (int)q;
|
||||
result[1] = (int)r;
|
||||
return (r << 32) | (q & LONG_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1473,5 +1766,4 @@ class MutableBigInteger {
|
||||
mod.subtract(t1);
|
||||
return mod;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2011 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6274390
|
||||
* @bug 6274390 7082971
|
||||
* @summary Verify {float, double}Value methods work with condensed representation
|
||||
* @run main FloatDoubleValueTests
|
||||
* @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests
|
||||
@ -79,6 +79,7 @@ public class FloatDoubleValueTests {
|
||||
// and double.
|
||||
static void testFloatDoubleValue() {
|
||||
long longValues[] = {
|
||||
Long.MIN_VALUE, // -2^63
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user