8238669: Long.divideUnsigned is extremely slow for certain values (Needs to be Intrinsic)
Reviewed-by: bpb
This commit is contained in:
parent
365f19c8e1
commit
0efdde188b
@ -1668,24 +1668,13 @@ public final class Long extends Number
|
|||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public static long divideUnsigned(long dividend, long divisor) {
|
public static long divideUnsigned(long dividend, long divisor) {
|
||||||
if (divisor < 0L) { // signed comparison
|
/* See Hacker's Delight (2nd ed), section 9.3 */
|
||||||
// Answer must be 0 or 1 depending on relative magnitude
|
if (divisor >= 0) {
|
||||||
// of dividend and divisor.
|
final long q = (dividend >>> 1) / divisor << 1;
|
||||||
return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
|
final long r = dividend - q * divisor;
|
||||||
}
|
return q + ((r | ~(r - divisor)) >>> (Long.SIZE - 1));
|
||||||
|
|
||||||
if (dividend > 0) // Both inputs non-negative
|
|
||||||
return dividend/divisor;
|
|
||||||
else {
|
|
||||||
/*
|
|
||||||
* For simple code, leveraging BigInteger. Longer and faster
|
|
||||||
* code written directly in terms of operations on longs is
|
|
||||||
* possible; see "Hacker's Delight" for divide and remainder
|
|
||||||
* algorithms.
|
|
||||||
*/
|
|
||||||
return toUnsignedBigInteger(dividend).
|
|
||||||
divide(toUnsignedBigInteger(divisor)).longValue();
|
|
||||||
}
|
}
|
||||||
|
return (dividend & ~(dividend - divisor)) >>> (Long.SIZE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1701,15 +1690,33 @@ public final class Long extends Number
|
|||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public static long remainderUnsigned(long dividend, long divisor) {
|
public static long remainderUnsigned(long dividend, long divisor) {
|
||||||
if (dividend > 0 && divisor > 0) { // signed comparisons
|
/* See Hacker's Delight (2nd ed), section 9.3 */
|
||||||
return dividend % divisor;
|
if (divisor >= 0) {
|
||||||
} else {
|
final long q = (dividend >>> 1) / divisor << 1;
|
||||||
if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor
|
final long r = dividend - q * divisor;
|
||||||
return dividend;
|
/*
|
||||||
else
|
* Here, 0 <= r < 2 * divisor
|
||||||
return toUnsignedBigInteger(dividend).
|
* (1) When 0 <= r < divisor, the remainder is simply r.
|
||||||
remainder(toUnsignedBigInteger(divisor)).longValue();
|
* (2) Otherwise the remainder is r - divisor.
|
||||||
|
*
|
||||||
|
* In case (1), r - divisor < 0. Applying ~ produces a long with
|
||||||
|
* sign bit 0, so >> produces 0. The returned value is thus r.
|
||||||
|
*
|
||||||
|
* In case (2), a similar reasoning shows that >> produces -1,
|
||||||
|
* so the returned value is r - divisor.
|
||||||
|
*/
|
||||||
|
return r - ((~(r - divisor) >> (Long.SIZE - 1)) & divisor);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* (1) When dividend >= 0, the remainder is dividend.
|
||||||
|
* (2) Otherwise
|
||||||
|
* (2.1) When dividend < divisor, the remainder is dividend.
|
||||||
|
* (2.2) Otherwise the remainder is dividend - divisor
|
||||||
|
*
|
||||||
|
* A reasoning similar to the above shows that the returned value
|
||||||
|
* is as expected.
|
||||||
|
*/
|
||||||
|
return dividend - (((dividend & ~(dividend - divisor)) >> (Long.SIZE - 1)) & divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit Twiddling
|
// Bit Twiddling
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2009, 2020, 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
|
||||||
@ -375,24 +375,54 @@ public class Unsigned {
|
|||||||
|
|
||||||
private static int testDivideAndRemainder() {
|
private static int testDivideAndRemainder() {
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
|
long TWO_31 = 1L << Integer.SIZE - 1;
|
||||||
|
long TWO_32 = 1L << Integer.SIZE;
|
||||||
|
long TWO_33 = 1L << Integer.SIZE + 1;
|
||||||
|
BigInteger NINETEEN = BigInteger.valueOf(19L);
|
||||||
|
BigInteger TWO_63 = BigInteger.ONE.shiftLeft(Long.SIZE - 1);
|
||||||
|
BigInteger TWO_64 = BigInteger.ONE.shiftLeft(Long.SIZE);
|
||||||
|
|
||||||
BigInteger[] inRange = {
|
BigInteger[] inRange = {
|
||||||
BigInteger.valueOf(0L),
|
BigInteger.ZERO,
|
||||||
BigInteger.valueOf(1L),
|
BigInteger.ONE,
|
||||||
BigInteger.valueOf(10L),
|
BigInteger.TEN,
|
||||||
BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1
|
NINETEEN,
|
||||||
BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE
|
|
||||||
BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1
|
|
||||||
|
|
||||||
BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
|
BigInteger.valueOf(TWO_31 - 19L),
|
||||||
BigInteger.valueOf(MAX_UNSIGNED_INT),
|
BigInteger.valueOf(TWO_31 - 10L),
|
||||||
|
BigInteger.valueOf(TWO_31 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_31),
|
||||||
|
BigInteger.valueOf(TWO_31 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_31 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_31 + 19L),
|
||||||
|
|
||||||
BigInteger.valueOf(Long.MAX_VALUE - 1L),
|
BigInteger.valueOf(TWO_32 - 19L),
|
||||||
BigInteger.valueOf(Long.MAX_VALUE),
|
BigInteger.valueOf(TWO_32 - 10L),
|
||||||
BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
|
BigInteger.valueOf(TWO_32 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_32),
|
||||||
|
BigInteger.valueOf(TWO_32 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_32 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_32 - 19L),
|
||||||
|
|
||||||
TWO.pow(64).subtract(BigInteger.ONE)
|
BigInteger.valueOf(TWO_33 - 19L),
|
||||||
|
BigInteger.valueOf(TWO_33 - 10L),
|
||||||
|
BigInteger.valueOf(TWO_33 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_33),
|
||||||
|
BigInteger.valueOf(TWO_33 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_33 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_33 + 19L),
|
||||||
|
|
||||||
|
TWO_63.subtract(NINETEEN),
|
||||||
|
TWO_63.subtract(BigInteger.TEN),
|
||||||
|
TWO_63.subtract(BigInteger.ONE),
|
||||||
|
TWO_63,
|
||||||
|
TWO_63.add(BigInteger.ONE),
|
||||||
|
TWO_63.add(BigInteger.TEN),
|
||||||
|
TWO_63.add(NINETEEN),
|
||||||
|
|
||||||
|
TWO_64.subtract(NINETEEN),
|
||||||
|
TWO_64.subtract(BigInteger.TEN),
|
||||||
|
TWO_64.subtract(BigInteger.ONE),
|
||||||
};
|
};
|
||||||
|
|
||||||
for(BigInteger dividend : inRange) {
|
for(BigInteger dividend : inRange) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user