Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions nitrite/src/main/java/org/dizitart/no2/common/util/Numbers.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,39 @@ private Numbers() {
public static int compare(Number x, Number y) {
if (isSpecial(x) || isSpecial(y)) {
return Double.compare(x.doubleValue(), y.doubleValue());
} else {
return toBigDecimal(x).compareTo(toBigDecimal(y));
}

// Every index key comparison lands here, and going through BigDecimal allocates two
// objects per call. The common cases can be answered exactly without it: any two
// integral primitives fit a long, two doubles or two floats compare as themselves
// once NaN and the infinities are out of the way (with -0.0 and 0.0 equal, as
// BigDecimal treats them), and two BigDecimals or two BigIntegers already have a
// compareTo. Everything else, and every mixed pairing, keeps the exact conversion.
if (isIntegral(x) && isIntegral(y)) {
return Long.compare(x.longValue(), y.longValue());
}
if (x instanceof Double && y instanceof Double) {
return compareFinite(x.doubleValue(), y.doubleValue());
}
if (x instanceof Float && y instanceof Float) {
return compareFinite(x.floatValue(), y.floatValue());
}
if (x instanceof BigDecimal && y instanceof BigDecimal) {
return ((BigDecimal) x).compareTo((BigDecimal) y);
}
if (x instanceof BigInteger && y instanceof BigInteger) {
return ((BigInteger) x).compareTo((BigInteger) y);
}
return toBigDecimal(x).compareTo(toBigDecimal(y));
}

private static boolean isIntegral(Number number) {
return number instanceof Long || number instanceof Integer
|| number instanceof Short || number instanceof Byte;
}

private static int compareFinite(double a, double b) {
return a < b ? -1 : (a > b ? 1 : 0);
}

private static boolean isSpecial(Number number) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ public static Collection<Object[]> data() {
{Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 0},
{Double.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, -1},
{Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 0},
// same-type fast paths must agree with the BigDecimal conversion
{Long.MAX_VALUE, Long.MIN_VALUE, 1},
{Long.MIN_VALUE, Long.MAX_VALUE, -1},
{Long.MAX_VALUE, Long.MAX_VALUE - 1, 1},
{(byte) 3, 3L, 0},
{(short) -2, -1, -1},
{Integer.MIN_VALUE, Long.MIN_VALUE, 1},
{0.0, -0.0, 0},
{-0.0, 0.0, 0},
{1.5, 1.25, 1},
{1.5f, 1.75f, -1},
{Double.NaN, 1.0, 1},
{1.0, Double.NaN, -1},
{0.1f, 0.1, 1}, // 0.1f widens to 0.10000000149, above 0.1: mixed types keep the exact path
{BigInteger.TEN, BigInteger.ONE, 1},
{new BigDecimal("2.50"), new BigDecimal("2.5"), 0},
{Long.MAX_VALUE, Double.MAX_VALUE, -1},
{Long.MAX_VALUE, new BigInteger("9223372036854775808"), -1},
});
}

Expand Down
Loading