@SuppressWarnings("unchecked")
    public static int compare(Comparable lhs, Comparable rhs) {
        Class lhsClass = lhs.getClass();
        Class rhsClass = rhs.getClass();
        assert lhsClass != rhsClass;
        assert lhs instanceof Number;
        assert rhs instanceof Number;

        Number lhsNumber = (Number) lhs;
        Number rhsNumber = (Number) rhs;

        if (isDoubleRepresentable(lhsClass)) {
            if (isDoubleRepresentable(rhsClass)) {
                return Double.compare(lhsNumber.doubleValue(), rhsNumber.doubleValue());
            } else if (isLongRepresentable(rhsClass)) {
                return -Integer.signum(compareLongWithDouble(rhsNumber.longValue(), lhsNumber.doubleValue()));
            }
        } else if (isLongRepresentable(lhsClass)) {
            if (isDoubleRepresentable(rhsClass)) {
                return compareLongWithDouble(lhsNumber.longValue(), rhsNumber.doubleValue());
            } else if (isLongRepresentable(rhsClass)) {
                return Long.compare(lhsNumber.longValue(), rhsNumber.longValue());
            }
        }

        return lhs.compareTo(rhs);
    }
@Test
    public void testCompare() {
        assertCompare(1L, 2, -1);
        assertCompare(1, 1L, 0);
        assertCompare(1, (short) 1, 0);
        assertCompare(1, (byte) 1, 0);

        assertCompare(1, 1.1, -1);
        // 1.100000000000000088817841970012523233890533447265625 < 1.10000002384185791015625
        assertCompare(1.1, 1.1F, -1);
        assertCompare(1, 1.0, 0);
        assertCompare(1, 1.0F, 0);
        assertCompare(1.0F, 1.0, 0);
        assertCompare(1.5F, 1.5, 0);
        assertCompare(1.1F, (double) 1.1F, 0);

        assertCompare(0, 0.0, 0);
        assertCompare(0, -0.0, +1);
        assertCompare(Long.MIN_VALUE, Double.NEGATIVE_INFINITY, +1);
        assertCompare(Long.MAX_VALUE, Double.POSITIVE_INFINITY, -1);
        assertCompare(0, Double.NaN, -1);
        assertCompare(Long.MAX_VALUE, Double.NaN, -1);

        assertCompare(Long.MAX_VALUE, Long.MAX_VALUE + 5000.0, -1);
        assertCompare(Long.MIN_VALUE, Long.MIN_VALUE - 5000.0, +1);

        assertCompare(1L << 53, 0x1p53, 0);
        // with Double, all things are possible
        assertCompare(1L << 53, 0x1p53 + 1, 0);
        assertCompare(1L << 53, 0x1p53 - 1, +1);
        assertCompare((1L << 53) - 1, 0x1p53 - 1, 0);
        assertCompare((1L << 53) + 2, 0x1p53 + 2, 0);

        assertCompare(-(1L << 53), -0x1p53, 0);
        assertCompare(-(1L << 53), -0x1p53 - 1, 0);
        assertCompare(-(1L << 53), -0x1p53 + 1, -1);
        assertCompare(-(1L << 53) + 1, -0x1p53 + 1, 0);
        assertCompare(-(1L << 53) - 2, -0x1p53 - 2, 0);

        assertCompare(Integer.MAX_VALUE, Long.MAX_VALUE, -1);
        assertCompare(Integer.MIN_VALUE, Long.MIN_VALUE, +1);
    }