JDK-6582946 : Add suite of compare(T, T) methods for ints, longs etc
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 7
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-07-19
  • Updated: 2017-05-16
  • Resolved: 2009-10-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b74Fixed
Related Reports
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
Add following 'static compare' methods:

// Integer.java
public static int compare(int a, int b) {
	return (a < b)? -1: (a == b)? 0: 1;
}

// Long.java
public static int compare(long a, long b) {
	return (a < b)? -1: (a == b)? 0: 1;
}

// Double.java
public static int compare(long a, double b) {
	// precise comparison, i.e. 40000000000000001L should be greater then 40000000000000000.0 (with == operator they are equal)
	// ...
}
public static int compare(double a, long b) {
	// ... same as above
}

// Float.java
public static int compare(float f, int i) {
	return Double.compare(f, (double) i); // or Double.compare(f, (long) i) or maybe something more efficient
}

public static int compare(int i, float f) {
	return Double.compare((double) i, f); // or Double.compare((long) i, f) or maybe something more efficient
}

'static compare' methods could also be added to Byte, Short, Character and Boolean just for consistency.


JUSTIFICATION :
Absence of Integer.compare(int, int) and Long.compare(long, long) often leads to quite common bug pattern where substraction is used (substraction is wrong in general due to overflow).

Absence of Double.compare(long, double) often leads to using plain comparison operators (i.e. <, >, = etc), which is not wholly satisfactory due to precision loss.

Note: In order to be consistent with Double.compare(double, double) and Float.compare(float, float):
1. NaN should be greater then any integer number;
2. -0.0 should be less then integer zero.


CUSTOMER SUBMITTED WORKAROUND :
Workaround for Integer.compare(int, int) and Long.compare(long, long)

1. Using boxing
I.e.
   ((Integer) a).compareTo(b)
instead of
   Integer.compare(a, b)
But it looks like less efficient way then proposed

2. Duplicate corrent comparison code everywhere it's needed
   (a < b)? -1: (a == b)? 0: 1

Workaround for Double.compare(long, double)

1. Write own precise comparison code

Comments
SUGGESTED FIX # HG changeset patch # User martin # Date 1253669458 25200 # Node ID eb92c939b8a723f122c92724f818e9e63a75674d # Parent bbb543254c6362b3cdba2b5d049fe931a58408af 6582946: Add suite of compare(T, T) methods for ints, longs etc Reviewed-by: darcy Contributed-by: ###@###.### --- a/src/share/classes/java/lang/Boolean.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Boolean.java Tue Sep 22 18:30:58 2009 -0700 @@ -255,7 +255,25 @@ public final class Boolean implements ja * @since 1.5 */ public int compareTo(Boolean b) { - return (b.value == value ? 0 : (value ? 1 : -1)); + return compare(this.value, b.value); + } + + /** + * Compares two {@code boolean} values. + * The value returned is identical to what would be returned by: + * <pre> + * Boolean.valueOf(x).compareTo(Boolean.valueOf(y)) + * </pre> + * + * @param x the first {@code boolean} to compare + * @param y the second {@code boolean} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code !x && y}; and + * a value greater than {@code 0} if {@code x && !y} + * @since 1.7 + */ + public static int compare(boolean x, boolean y) { + return (x == y) ? 0 : (x ? 1 : -1); } private static boolean toBoolean(String name) { --- a/src/share/classes/java/lang/Byte.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Byte.java Tue Sep 22 18:30:58 2009 -0700 @@ -418,7 +418,25 @@ public final class Byte extends Number i * @since 1.2 */ public int compareTo(Byte anotherByte) { - return this.value - anotherByte.value; + return compare(this.value, anotherByte.value); + } + + /** + * Compares two {@code byte} values numerically. + * The value returned is identical to what would be returned by: + * <pre> + * Byte.valueOf(x).compareTo(Byte.valueOf(y)) + * </pre> + * + * @param x the first {@code byte} to compare + * @param y the second {@code byte} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 1.7 + */ + public static int compare(byte x, byte y) { + return x - y; } /** --- a/src/share/classes/java/lang/Character.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Character.java Tue Sep 22 18:30:58 2009 -0700 @@ -4964,7 +4964,25 @@ class Character extends Object implement * @since 1.2 */ public int compareTo(Character anotherCharacter) { - return this.value - anotherCharacter.value; + return compare(this.value, anotherCharacter.value); + } + + /** + * Compares two {@code char} values numerically. + * The value returned is identical to what would be returned by: + * <pre> + * Character.valueOf(x).compareTo(Character.valueOf(y)) + * </pre> + * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 1.7 + */ + public static int compare(char x, char y) { + return x - y; } /** --- a/src/share/classes/java/lang/Integer.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Integer.java Tue Sep 22 18:30:58 2009 -0700 @@ -1010,9 +1010,25 @@ public final class Integer extends Numbe * @since 1.2 */ public int compareTo(Integer anotherInteger) { - int thisVal = this.value; - int anotherVal = anotherInteger.value; - return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1)); + return compare(this.value, anotherInteger.value); + } + + /** + * Compares two {@code int} values numerically. + * The value returned is identical to what would be returned by: + * <pre> + * Integer.valueOf(x).compareTo(Integer.valueOf(y)) + * </pre> + * + * @param x the first {@code int} to compare + * @param y the second {@code int} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 1.7 + */ + public static int compare(int x, int y) { + return (x < y) ? -1 : ((x == y) ? 0 : 1); } --- a/src/share/classes/java/lang/Long.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Long.java Tue Sep 22 18:30:58 2009 -0700 @@ -950,9 +950,25 @@ public final class Long extends Number i * @since 1.2 */ public int compareTo(Long anotherLong) { - long thisVal = this.value; - long anotherVal = anotherLong.value; - return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1)); + return compare(this.value, anotherLong.value); + } + + /** + * Compares two {@code long} values numerically. + * The value returned is identical to what would be returned by: + * <pre> + * Long.valueOf(x).compareTo(Long.valueOf(y)) + * </pre> + * + * @param x the first {@code long} to compare + * @param y the second {@code long} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 1.7 + */ + public static int compare(long x, long y) { + return (x < y) ? -1 : ((x == y) ? 0 : 1); } --- a/src/share/classes/java/lang/Short.java Tue Sep 22 18:30:58 2009 -0700 +++ b/src/share/classes/java/lang/Short.java Tue Sep 22 18:30:58 2009 -0700 @@ -423,7 +423,25 @@ public final class Short extends Number * @since 1.2 */ public int compareTo(Short anotherShort) { - return this.value - anotherShort.value; + return compare(this.value, anotherShort.value); + } + + /** + * Compares two {@code short} values numerically. + * The value returned is identical to what would be returned by: + * <pre> + * Short.valueOf(x).compareTo(Short.valueOf(y)) + * </pre> + * + * @param x the first {@code short} to compare + * @param y the second {@code short} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 1.7 + */ + public static int compare(short x, short y) { + return x - y; } /** --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/Compare.java Tue Sep 22 18:30:58 2009 -0700 @@ -0,0 +1,142 @@ +/* + * Copyright 2009 Google, Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6582946 + * @summary Test the primitive wrappers compare and compareTo methods + */ + +import java.util.Random; + +public class Compare { + + final Random rnd = new Random(); + + boolean toBoolean(long x) { return x > 0; } + + void compareAll(long x, long y) { + check(Double.compare(x, y) == + Double.valueOf(x).compareTo(Double.valueOf(y))); + check(Float.compare(x, y) == + Float.valueOf(x).compareTo(Float.valueOf(y))); + check(Long.compare(x, y) == + Long.valueOf(x).compareTo(Long.valueOf(y))); + check(Integer.compare((int) x, (int) y) == + Integer.valueOf((int) x).compareTo(Integer.valueOf((int) y))); + check(Short.compare((short) x, (short) y) == + Short.valueOf((short) x).compareTo(Short.valueOf((short) y))); + check(Character.compare((char) x, (char) y) == + Character.valueOf((char) x).compareTo(Character.valueOf((char) y))); + check(Byte.compare((byte) x, (byte) y) == + Byte.valueOf((byte) x).compareTo(Byte.valueOf((byte) y))); + check(Boolean.compare(toBoolean(x), toBoolean(y)) == + Boolean.valueOf(toBoolean(x)).compareTo(Boolean.valueOf(toBoolean(y)))); + + check(Double.compare(x, y) == -Double.compare(y, x)); + check(Float.compare(x, y) == -Float.compare(y, x)); + check(Long.compare(x, y) == -Long.compare(y, x)); + check(Integer.compare((int) x, (int) y) == + -Integer.compare((int) y, (int) x)); + check(Short.compare((short) x, (short) y) == + -Short.compare((short) y, (short) x)); + check(Character.compare((char) x, (char) y) == + -Character.compare((char) y, (char) x)); + check(Byte.compare((byte) x, (byte) y) == + -Byte.compare((byte) y, (byte) x)); + + equal(Long.compare(x, y), + x < y ? -1 : x > y ? 1 : 0); + + { + int a = (int) x, b = (int) y; + equal(Integer.compare(a, b), + a < b ? -1 : a > b ? 1 : 0); + } + + { + short a = (short) x, b = (short) y; + equal(Short.compare(a, b), + a - b); + } + + { + char a = (char) x, b = (char) y; + equal(Character.compare(a, b), + a - b); + } + + { + byte a = (byte) x, b = (byte) y; + equal(Byte.compare(a, b), + a - b); + } + + { + boolean a = toBoolean(x), b = toBoolean(y); + equal(Boolean.compare(a, b), + a == b ? 0 : a ? 1 : -1); + } + } + + void test(String args[]) throws Exception { + long[] longs = { + Long.MIN_VALUE, + Integer.MIN_VALUE, + Short.MIN_VALUE, + Character.MIN_VALUE, + Byte.MIN_VALUE, + -1, 0, 1, + Byte.MAX_VALUE, + Character.MAX_VALUE, + Short.MAX_VALUE, + Integer.MAX_VALUE, + Long.MAX_VALUE, + rnd.nextLong(), + rnd.nextInt(), + }; + + for (long x : longs) { + for (long y : longs) { + compareAll(x, y); + } + } + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new Compare().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +}
28-09-2009

PUBLIC COMMENTS See http://hg.openjdk.java.net/jdk7/tl/jdk/rev/eb92c939b8a7
28-09-2009

EVALUATION Contribution-forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=22424
25-11-2007