mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8331907: BigInteger and BigDecimal should use optimized division
Reviewed-by: rgiulietti, bpb
This commit is contained in:
parent
440782e016
commit
beea5305b0
4 changed files with 89 additions and 186 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, 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
|
||||
|
@ -5680,18 +5680,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||
|
||||
tmp = (dividendHi << shift) | (dividendLo >>> 64 - shift);
|
||||
long u2 = tmp & LONG_MASK;
|
||||
long q1, r_tmp;
|
||||
if (v1 == 1) {
|
||||
q1 = tmp;
|
||||
r_tmp = 0;
|
||||
} else if (tmp >= 0) {
|
||||
q1 = tmp / v1;
|
||||
r_tmp = tmp - q1 * v1;
|
||||
} else {
|
||||
long[] rq = divRemNegativeLong(tmp, v1);
|
||||
q1 = rq[1];
|
||||
r_tmp = rq[0];
|
||||
}
|
||||
long q1 = Long.divideUnsigned(tmp, v1);
|
||||
long r_tmp = Long.remainderUnsigned(tmp, v1);
|
||||
|
||||
while(q1 >= DIV_NUM_BASE || unsignedLongCompare(q1*v0, make64(r_tmp, u1))) {
|
||||
q1--;
|
||||
|
@ -5702,18 +5692,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||
|
||||
tmp = mulsub(u2,u1,v1,v0,q1);
|
||||
u1 = tmp & LONG_MASK;
|
||||
long q0;
|
||||
if (v1 == 1) {
|
||||
q0 = tmp;
|
||||
r_tmp = 0;
|
||||
} else if (tmp >= 0) {
|
||||
q0 = tmp / v1;
|
||||
r_tmp = tmp - q0 * v1;
|
||||
} else {
|
||||
long[] rq = divRemNegativeLong(tmp, v1);
|
||||
q0 = rq[1];
|
||||
r_tmp = rq[0];
|
||||
}
|
||||
long q0 = Long.divideUnsigned(tmp, v1);
|
||||
r_tmp = Long.remainderUnsigned(tmp, v1);
|
||||
|
||||
while(q0 >= DIV_NUM_BASE || unsignedLongCompare(q0*v0,make64(r_tmp,u0))) {
|
||||
q0--;
|
||||
|
@ -5793,37 +5773,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the quotient and remainder of dividing a negative long by
|
||||
* another long.
|
||||
*
|
||||
* @param n the numerator; must be negative
|
||||
* @param d the denominator; must not be unity
|
||||
* @return a two-element {@code long} array with the remainder and quotient in
|
||||
* the initial and final elements, respectively
|
||||
*/
|
||||
private static long[] divRemNegativeLong(long n, long d) {
|
||||
assert n < 0 : "Non-negative numerator " + n;
|
||||
assert d != 1 : "Unity denominator";
|
||||
|
||||
// Approximate the quotient and remainder
|
||||
long q = (n >>> 1) / (d >>> 1);
|
||||
long r = n - q * d;
|
||||
|
||||
// Correct the approximation
|
||||
while (r < 0) {
|
||||
r += d;
|
||||
q--;
|
||||
}
|
||||
while (r >= d) {
|
||||
r -= d;
|
||||
q++;
|
||||
}
|
||||
|
||||
// n - q*d == r && 0 <= r < d, hence we're done.
|
||||
return new long[] {r, q};
|
||||
}
|
||||
|
||||
private static long make64(long hi, long lo) {
|
||||
return hi<<32 | lo;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, 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
|
||||
|
@ -1092,9 +1092,9 @@ class MutableBigInteger {
|
|||
|
||||
// Special case of one word dividend
|
||||
if (intLen == 1) {
|
||||
long dividendValue = value[offset] & LONG_MASK;
|
||||
int q = (int) (dividendValue / divisorLong);
|
||||
int r = (int) (dividendValue - q * divisorLong);
|
||||
int dividendValue = value[offset];
|
||||
int q = Integer.divideUnsigned(dividendValue, divisor);
|
||||
int r = Integer.remainderUnsigned(dividendValue, divisor);
|
||||
quotient.value[0] = q;
|
||||
quotient.intLen = (q == 0) ? 0 : 1;
|
||||
quotient.offset = 0;
|
||||
|
@ -1106,41 +1106,17 @@ class MutableBigInteger {
|
|||
quotient.offset = 0;
|
||||
quotient.intLen = intLen;
|
||||
|
||||
// Normalize the divisor
|
||||
int shift = Integer.numberOfLeadingZeros(divisor);
|
||||
|
||||
int rem = value[offset];
|
||||
long remLong = rem & LONG_MASK;
|
||||
if (remLong < divisorLong) {
|
||||
quotient.value[0] = 0;
|
||||
} else {
|
||||
quotient.value[0] = (int)(remLong / divisorLong);
|
||||
rem = (int) (remLong - (quotient.value[0] * divisorLong));
|
||||
remLong = rem & LONG_MASK;
|
||||
}
|
||||
int xlen = intLen;
|
||||
while (--xlen > 0) {
|
||||
long dividendEstimate = (remLong << 32) |
|
||||
long rem = 0;
|
||||
for (int xlen = intLen; xlen > 0; xlen--) {
|
||||
long dividendEstimate = (rem << 32) |
|
||||
(value[offset + intLen - xlen] & LONG_MASK);
|
||||
int q;
|
||||
if (dividendEstimate >= 0) {
|
||||
q = (int) (dividendEstimate / divisorLong);
|
||||
rem = (int) (dividendEstimate - q * divisorLong);
|
||||
} else {
|
||||
long tmp = divWord(dividendEstimate, divisor);
|
||||
q = (int) (tmp & LONG_MASK);
|
||||
rem = (int) (tmp >>> 32);
|
||||
}
|
||||
int q = (int) Long.divideUnsigned(dividendEstimate, divisorLong);
|
||||
rem = Long.remainderUnsigned(dividendEstimate, divisorLong);
|
||||
quotient.value[intLen - xlen] = q;
|
||||
remLong = rem & LONG_MASK;
|
||||
}
|
||||
|
||||
quotient.normalize();
|
||||
// Unnormalize
|
||||
if (shift > 0)
|
||||
return rem % divisor;
|
||||
else
|
||||
return rem;
|
||||
return (int)rem;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1557,14 +1533,8 @@ class MutableBigInteger {
|
|||
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);
|
||||
}
|
||||
qhat = (int) Long.divideUnsigned(nChunk, dhLong);
|
||||
qrem = (int) Long.remainderUnsigned(nChunk, dhLong);
|
||||
}
|
||||
|
||||
if (qhat == 0)
|
||||
|
@ -1616,14 +1586,8 @@ class MutableBigInteger {
|
|||
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);
|
||||
}
|
||||
qhat = (int) Long.divideUnsigned(nChunk, dhLong);
|
||||
qrem = (int) Long.remainderUnsigned(nChunk, dhLong);
|
||||
}
|
||||
if (qhat != 0) {
|
||||
if (!skipCorrection) { // Correct qhat
|
||||
|
@ -1732,14 +1696,8 @@ class MutableBigInteger {
|
|||
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);
|
||||
}
|
||||
qhat = (int) Long.divideUnsigned(nChunk, dhLong);
|
||||
qrem = (int) Long.remainderUnsigned(nChunk, dhLong);
|
||||
}
|
||||
|
||||
if (qhat == 0)
|
||||
|
@ -1834,40 +1792,6 @@ class MutableBigInteger {
|
|||
return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 remainder value and
|
||||
* low 32 bits contain quotient value.
|
||||
*/
|
||||
static long divWord(long n, int d) {
|
||||
long dLong = d & LONG_MASK;
|
||||
long r;
|
||||
long q;
|
||||
if (dLong == 1) {
|
||||
q = (int)n;
|
||||
r = 0;
|
||||
return (r << 32) | (q & LONG_MASK);
|
||||
}
|
||||
|
||||
// Approximate the quotient and remainder
|
||||
q = (n >>> 1) / (dLong >>> 1);
|
||||
r = n - q*dLong;
|
||||
|
||||
// Correct the approximation
|
||||
while (r < 0) {
|
||||
r += dLong;
|
||||
q--;
|
||||
}
|
||||
while (r >= dLong) {
|
||||
r -= dLong;
|
||||
q++;
|
||||
}
|
||||
// n - q*dlong == r && 0 <= r <dLong, hence we're done.
|
||||
return (r << 32) | (q & LONG_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the integer square root {@code floor(sqrt(this))} where
|
||||
* {@code sqrt(.)} denotes the mathematical square root. The contents of
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue