Skip to content

Commit 6ae462c

Browse files
committed
8238669: Long.divideUnsigned is extremely slow for certain values (Needs to be Intrinsic)
1 parent 4b3a0b7 commit 6ae462c

File tree

2 files changed

+58
-41
lines changed

2 files changed

+58
-41
lines changed

src/java.base/share/classes/java/lang/Long.java

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,24 +1668,13 @@ public static int compareUnsigned(long x, long y) {
16681668
* @since 1.8
16691669
*/
16701670
public static long divideUnsigned(long dividend, long divisor) {
1671-
if (divisor < 0L) { // signed comparison
1672-
// Answer must be 0 or 1 depending on relative magnitude
1673-
// of dividend and divisor.
1674-
return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
1675-
}
1676-
1677-
if (dividend > 0) // Both inputs non-negative
1678-
return dividend/divisor;
1679-
else {
1680-
/*
1681-
* For simple code, leveraging BigInteger. Longer and faster
1682-
* code written directly in terms of operations on longs is
1683-
* possible; see "Hacker's Delight" for divide and remainder
1684-
* algorithms.
1685-
*/
1686-
return toUnsignedBigInteger(dividend).
1687-
divide(toUnsignedBigInteger(divisor)).longValue();
1671+
// See Hacker's Delight (2nd ed), section 9.3
1672+
if (divisor >= 0) {
1673+
final long q = (dividend >>> 1) / divisor << 1;
1674+
final long r = dividend - q * divisor;
1675+
return q + ((r | ~(r - divisor)) >>> Long.SIZE - 1);
16881676
}
1677+
return (dividend & ~(dividend - divisor)) >>> Long.SIZE - 1;
16891678
}
16901679

16911680
/**
@@ -1701,15 +1690,13 @@ public static long divideUnsigned(long dividend, long divisor) {
17011690
* @since 1.8
17021691
*/
17031692
public static long remainderUnsigned(long dividend, long divisor) {
1704-
if (dividend > 0 && divisor > 0) { // signed comparisons
1705-
return dividend % divisor;
1706-
} else {
1707-
if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor
1708-
return dividend;
1709-
else
1710-
return toUnsignedBigInteger(dividend).
1711-
remainder(toUnsignedBigInteger(divisor)).longValue();
1693+
// See Hacker's Delight (2nd ed), section 9.3
1694+
if (divisor >= 0) {
1695+
final long q = (dividend >>> 1) / divisor << 1;
1696+
final long r = dividend - q * divisor;
1697+
return r - (~(r - divisor) >> Long.SIZE - 1 & divisor);
17121698
}
1699+
return dividend - ((dividend & ~(dividend - divisor)) >> Long.SIZE - 1 & divisor);
17131700
}
17141701

17151702
// Bit Twiddling

test/jdk/java/lang/Long/Unsigned.java

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -375,24 +375,54 @@ private static int testUnsignedOverflow(String s, int radix, boolean exception)
375375

376376
private static int testDivideAndRemainder() {
377377
int errors = 0;
378-
long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
378+
long TWO_31 = 1L << Integer.SIZE - 1;
379+
long TWO_32 = 1L << Integer.SIZE;
380+
long TWO_33 = 1L << Integer.SIZE + 1;
381+
BigInteger NINETEEN = BigInteger.valueOf(19L);
382+
BigInteger TWO_63 = BigInteger.ONE.shiftLeft(Long.SIZE - 1);
383+
BigInteger TWO_64 = BigInteger.ONE.shiftLeft(Long.SIZE);
379384

380385
BigInteger[] inRange = {
381-
BigInteger.valueOf(0L),
382-
BigInteger.valueOf(1L),
383-
BigInteger.valueOf(10L),
384-
BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1
385-
BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE
386-
BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1
387-
388-
BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
389-
BigInteger.valueOf(MAX_UNSIGNED_INT),
390-
391-
BigInteger.valueOf(Long.MAX_VALUE - 1L),
392-
BigInteger.valueOf(Long.MAX_VALUE),
393-
BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
394-
395-
TWO.pow(64).subtract(BigInteger.ONE)
386+
BigInteger.ZERO,
387+
BigInteger.ONE,
388+
BigInteger.TEN,
389+
NINETEEN,
390+
391+
BigInteger.valueOf(TWO_31 - 19L),
392+
BigInteger.valueOf(TWO_31 - 10L),
393+
BigInteger.valueOf(TWO_31 - 1L),
394+
BigInteger.valueOf(TWO_31),
395+
BigInteger.valueOf(TWO_31 + 1L),
396+
BigInteger.valueOf(TWO_31 + 10L),
397+
BigInteger.valueOf(TWO_31 + 19L),
398+
399+
BigInteger.valueOf(TWO_32 - 19L),
400+
BigInteger.valueOf(TWO_32 - 10L),
401+
BigInteger.valueOf(TWO_32 - 1L),
402+
BigInteger.valueOf(TWO_32),
403+
BigInteger.valueOf(TWO_32 + 1L),
404+
BigInteger.valueOf(TWO_32 + 10L),
405+
BigInteger.valueOf(TWO_32 - 19L),
406+
407+
BigInteger.valueOf(TWO_33 - 19L),
408+
BigInteger.valueOf(TWO_33 - 10L),
409+
BigInteger.valueOf(TWO_33 - 1L),
410+
BigInteger.valueOf(TWO_33),
411+
BigInteger.valueOf(TWO_33 + 1L),
412+
BigInteger.valueOf(TWO_33 + 10L),
413+
BigInteger.valueOf(TWO_33 + 19L),
414+
415+
TWO_63.subtract(NINETEEN),
416+
TWO_63.subtract(BigInteger.TEN),
417+
TWO_63.subtract(BigInteger.ONE),
418+
TWO_63,
419+
TWO_63.add(BigInteger.ONE),
420+
TWO_63.add(BigInteger.TEN),
421+
TWO_63.add(NINETEEN),
422+
423+
TWO_64.subtract(NINETEEN),
424+
TWO_64.subtract(BigInteger.TEN),
425+
TWO_64.subtract(BigInteger.ONE),
396426
};
397427

398428
for(BigInteger dividend : inRange) {

0 commit comments

Comments
 (0)