8331907: BigInteger and BigDecimal should use optimized division

Reviewed-by: rgiulietti, bpb
This commit is contained in:
Daniel Jeliński 2024-05-14 05:01:51 +00:00
parent 440782e016
commit beea5305b0
4 changed files with 89 additions and 186 deletions

View file

@ -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;
}