提交 60839a4f 编写于 作者: D darcy

7082971: More performance tuning of BigDecimal and other java.math classes

Reviewed-by: darcy
Contributed-by: sergey.kuksenko@oracle.com
上级 509f241d
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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> { ...@@ -353,27 +353,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
mag = trustedStripLeadingZeroInts(magnitude); 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 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 // 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++; cursor++;
}
if (cursor == len) { if (cursor == len) {
signum = 0; signum = 0;
mag = ZERO.mag; mag = ZERO.mag;
...@@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
numDigits = len - cursor; numDigits = len - cursor;
signum = sign; signum = sign;
// Pre-allocate array of expected size // Pre-allocate array of expected size
int numWords; int numWords;
if (len < 10) { if (len < 10) {
...@@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return new BigInteger(resultMag, cmp == signum ? 1 : -1); 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 &gt; 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 * 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 * 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> { ...@@ -1074,14 +1130,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int yIndex = y.length; int yIndex = y.length;
int result[] = new int[xIndex]; int result[] = new int[xIndex];
long sum = 0; long sum = 0;
if(yIndex==1) {
sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ;
result[xIndex] = (int)sum;
} else {
// Add common parts of both numbers // Add common parts of both numbers
while(yIndex > 0) { while(yIndex > 0) {
sum = (x[--xIndex] & LONG_MASK) + sum = (x[--xIndex] & LONG_MASK) +
(y[--yIndex] & LONG_MASK) + (sum >>> 32); (y[--yIndex] & LONG_MASK) + (sum >>> 32);
result[xIndex] = (int)sum; result[xIndex] = (int)sum;
} }
}
// Copy remainder of longer number while carry propagation is required // Copy remainder of longer number while carry propagation is required
boolean carry = (sum >>> 32 != 0); boolean carry = (sum >>> 32 != 0);
while (xIndex > 0 && carry) while (xIndex > 0 && carry)
...@@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return result; 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 &gt;= 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)}. * Returns a BigInteger whose value is {@code (this - val)}.
* *
...@@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
public BigInteger multiply(BigInteger val) { public BigInteger multiply(BigInteger val) {
if (val.signum == 0 || signum == 0) if (val.signum == 0 || signum == 0)
return ZERO; 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, int[] result = multiplyToLen(mag, mag.length,
val.mag, val.mag.length, null); val.mag, val.mag.length, null);
result = trustedStripLeadingZeroInts(result); 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> { ...@@ -1339,8 +1491,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q); a.divide(b, q, false);
return q.toBigInteger(this.signum == val.signum ? 1 : -1); return q.toBigInteger(this.signum * val.signum);
} }
/** /**
...@@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return shiftRight(-n); 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 nInts = n >>> 5;
int nBits = n & 0x1f; int nBits = n & 0x1f;
int magLen = mag.length; int magLen = mag.length;
...@@ -2094,8 +2251,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -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 | mag[j] >>> nBits2;
newMag[i] = mag[j] << nBits; newMag[i] = mag[j] << nBits;
} }
return newMag;
return new BigInteger(newMag, signum);
} }
/** /**
...@@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return 0; 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. * Compares this BigInteger with the specified Object for equality.
* *
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -160,7 +160,7 @@ class MutableBigInteger { ...@@ -160,7 +160,7 @@ class MutableBigInteger {
*/ */
BigDecimal toBigDecimal(int sign, int scale) { BigDecimal toBigDecimal(int sign, int scale) {
if (intLen == 0 || sign == 0) if (intLen == 0 || sign == 0)
return BigDecimal.valueOf(0, scale); return BigDecimal.zeroValueOf(scale);
int[] mag = getMagnitudeArray(); int[] mag = getMagnitudeArray();
int len = mag.length; int len = mag.length;
int d = mag[0]; int d = mag[0];
...@@ -171,7 +171,28 @@ class MutableBigInteger { ...@@ -171,7 +171,28 @@ class MutableBigInteger {
long v = (len == 2) ? long v = (len == 2) ?
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
d & LONG_MASK; 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 { ...@@ -543,6 +564,24 @@ class MutableBigInteger {
return (int)carry; 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 * Right shift this MutableBigInteger n bits, where n is
* less than 32. * less than 32.
...@@ -842,20 +881,20 @@ class MutableBigInteger { ...@@ -842,20 +881,20 @@ class MutableBigInteger {
rem = (int) (remLong - (quotient.value[0] * divisorLong)); rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
int xlen = intLen; int xlen = intLen;
int[] qWord = new int[2];
while (--xlen > 0) { while (--xlen > 0) {
long dividendEstimate = (remLong<<32) | long dividendEstimate = (remLong << 32) |
(value[offset + intLen - xlen] & LONG_MASK); (value[offset + intLen - xlen] & LONG_MASK);
int q;
if (dividendEstimate >= 0) { if (dividendEstimate >= 0) {
qWord[0] = (int) (dividendEstimate / divisorLong); q = (int) (dividendEstimate / divisorLong);
qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong); rem = (int) (dividendEstimate - q * divisorLong);
} else { } 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]; quotient.value[intLen - xlen] = q;
rem = qWord[1];
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
...@@ -879,40 +918,45 @@ class MutableBigInteger { ...@@ -879,40 +918,45 @@ class MutableBigInteger {
* *
*/ */
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) { MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
return divide(b,quotient,true);
}
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) {
if (b.intLen == 0) if (b.intLen == 0)
throw new ArithmeticException("BigInteger divide by zero"); throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero // Dividend is zero
if (intLen == 0) { if (intLen == 0) {
quotient.intLen = quotient.offset; quotient.intLen = quotient.offset;
return new MutableBigInteger(); return needReminder ? new MutableBigInteger() : null;
} }
int cmp = compare(b); int cmp = compare(b);
// Dividend less than divisor // Dividend less than divisor
if (cmp < 0) { if (cmp < 0) {
quotient.intLen = quotient.offset = 0; quotient.intLen = quotient.offset = 0;
return new MutableBigInteger(this); return needReminder ? new MutableBigInteger(this) : null;
} }
// Dividend equal to divisor // Dividend equal to divisor
if (cmp == 0) { if (cmp == 0) {
quotient.value[0] = quotient.intLen = 1; quotient.value[0] = quotient.intLen = 1;
quotient.offset = 0; quotient.offset = 0;
return new MutableBigInteger(); return needReminder ? new MutableBigInteger() : null;
} }
quotient.clear(); quotient.clear();
// Special case one word divisor // Special case one word divisor
if (b.intLen == 1) { if (b.intLen == 1) {
int r = divideOneWord(b.value[b.offset], quotient); int r = divideOneWord(b.value[b.offset], quotient);
if(needReminder) {
if (r == 0) if (r == 0)
return new MutableBigInteger(); return new MutableBigInteger();
return new MutableBigInteger(r); return new MutableBigInteger(r);
} else {
return null;
} }
}
// Copy divisor value to protect divisor return divideMagnitude(b, quotient, needReminder);
int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
return divideMagnitude(div, quotient);
} }
/** /**
...@@ -940,30 +984,72 @@ class MutableBigInteger { ...@@ -940,30 +984,72 @@ class MutableBigInteger {
if (d == 0) if (d == 0)
return divideOneWord((int)v, quotient) & LONG_MASK; return divideOneWord((int)v, quotient) & LONG_MASK;
else { else {
int[] div = new int[]{ d, (int)(v & LONG_MASK) }; return divideLongMagnitude(v, quotient).toLong();
return divideMagnitude(div, 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 * Divide this MutableBigInteger by the divisor.
* array. The quotient will be placed into the provided quotient object & * The quotient will be placed into the provided quotient object &
* the remainder object is returned. * the remainder object is returned.
*/ */
private MutableBigInteger divideMagnitude(int[] divisor, private MutableBigInteger divideMagnitude(MutableBigInteger div,
MutableBigInteger quotient) { MutableBigInteger quotient,
boolean needReminder ) {
// Remainder starts as dividend with space for a leading zero // assert div.intLen > 1
MutableBigInteger rem = new MutableBigInteger(new int[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); System.arraycopy(value, offset, rem.value, 1, intLen);
rem.intLen = intLen; rem.intLen = intLen;
rem.offset = 1; rem.offset = 1;
}
int nlen = rem.intLen; int nlen = rem.intLen;
// Set the quotient size // Set the quotient size
int dlen = divisor.length; final int limit = nlen - dlen + 1;
int limit = nlen - dlen + 1;
if (quotient.value.length < limit) { if (quotient.value.length < limit) {
quotient.value = new int[limit]; quotient.value = new int[limit];
quotient.offset = 0; quotient.offset = 0;
...@@ -971,14 +1057,6 @@ class MutableBigInteger { ...@@ -971,14 +1057,6 @@ class MutableBigInteger {
quotient.intLen = limit; quotient.intLen = limit;
int[] q = quotient.value; 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 // Must insert leading 0 in rem if its length did not change
if (rem.intLen == nlen) { if (rem.intLen == nlen) {
...@@ -990,10 +1068,9 @@ class MutableBigInteger { ...@@ -990,10 +1068,9 @@ class MutableBigInteger {
int dh = divisor[0]; int dh = divisor[0];
long dhLong = dh & LONG_MASK; long dhLong = dh & LONG_MASK;
int dl = divisor[1]; int dl = divisor[1];
int[] qWord = new int[2];
// D2 Initialize j // D2 Initialize j
for(int j=0; j<limit; j++) { for(int j=0; j<limit-1; j++) {
// D3 Calculate qhat // D3 Calculate qhat
// estimate qhat // estimate qhat
int qhat = 0; int qhat = 0;
...@@ -1013,9 +1090,9 @@ class MutableBigInteger { ...@@ -1013,9 +1090,9 @@ class MutableBigInteger {
qhat = (int) (nChunk / dhLong); qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong)); qrem = (int) (nChunk - (qhat * dhLong));
} else { } else {
divWord(qWord, nChunk, dh); long tmp = divWord(nChunk, dh);
qhat = qWord[0]; qhat = (int) (tmp & LONG_MASK);
qrem = qWord[1]; qrem = (int) (tmp >>> 32);
} }
} }
...@@ -1053,6 +1130,181 @@ class MutableBigInteger { ...@@ -1053,6 +1130,181 @@ class MutableBigInteger {
// Store the quotient digit // Store the quotient digit
q[j] = qhat; q[j] = qhat;
} // D7 loop on j } // 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 // D8 Unnormalize
if (shift > 0) if (shift > 0)
...@@ -1063,6 +1315,46 @@ class MutableBigInteger { ...@@ -1063,6 +1315,46 @@ class MutableBigInteger {
return rem; 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. * Compare two longs as if they were unsigned.
* Returns true iff one is bigger than two. * Returns true iff one is bigger than two.
...@@ -1075,19 +1367,22 @@ class MutableBigInteger { ...@@ -1075,19 +1367,22 @@ class MutableBigInteger {
* This method divides a long quantity by an int to estimate * This method divides a long quantity by an int to estimate
* qhat for two multi precision numbers. It is used when * qhat for two multi precision numbers. It is used when
* the signed value of n is less than zero. * 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 dLong = d & LONG_MASK;
long r;
long q;
if (dLong == 1) { if (dLong == 1) {
result[0] = (int)n; q = (int)n;
result[1] = 0; r = 0;
return; return (r << 32) | (q & LONG_MASK);
} }
// Approximate the quotient and remainder // Approximate the quotient and remainder
long q = (n >>> 1) / (dLong >>> 1); q = (n >>> 1) / (dLong >>> 1);
long r = n - q*dLong; r = n - q*dLong;
// Correct the approximation // Correct the approximation
while (r < 0) { while (r < 0) {
...@@ -1098,10 +1393,8 @@ class MutableBigInteger { ...@@ -1098,10 +1393,8 @@ class MutableBigInteger {
r -= dLong; r -= dLong;
q++; q++;
} }
// n - q*dlong == r && 0 <= r <dLong, hence we're done. // n - q*dlong == r && 0 <= r <dLong, hence we're done.
result[0] = (int)q; return (r << 32) | (q & LONG_MASK);
result[1] = (int)r;
} }
/** /**
...@@ -1473,5 +1766,4 @@ class MutableBigInteger { ...@@ -1473,5 +1766,4 @@ class MutableBigInteger {
mod.subtract(t1); mod.subtract(t1);
return mod; return mod;
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 6274390 * @bug 6274390 7082971
* @summary Verify {float, double}Value methods work with condensed representation * @summary Verify {float, double}Value methods work with condensed representation
* @run main FloatDoubleValueTests * @run main FloatDoubleValueTests
* @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests * @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests
...@@ -79,6 +79,7 @@ public class FloatDoubleValueTests { ...@@ -79,6 +79,7 @@ public class FloatDoubleValueTests {
// and double. // and double.
static void testFloatDoubleValue() { static void testFloatDoubleValue() {
long longValues[] = { long longValues[] = {
Long.MIN_VALUE, // -2^63
0, 0,
1, 1,
2, 2,
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册