Replaced all versions of binarySearch with better versions.
For float[] and double[], the new versions should run significantly faster than the old.
Removed some obsolete helper methods.
diff --git a/libcore/luni/src/main/java/java/util/Arrays.java b/libcore/luni/src/main/java/java/util/Arrays.java
index a864f78..c49a298 100644
--- a/libcore/luni/src/main/java/java/util/Arrays.java
+++ b/libcore/luni/src/main/java/java/util/Arrays.java
@@ -185,22 +185,21 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(byte[] array, byte value) {
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (value > array[mid]) {
- low = mid + 1;
- } else if (value == array[mid]) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- if (mid < 0) {
- return -1;
- }
+ int lo = 0;
+ int hi = array.length - 1;
- return -mid - (value < array[mid] ? 1 : 2);
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ byte midVal = array[mid];
+
+ if (midVal < value)
+ lo = mid + 1;
+ else if (midVal > value)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
}
/**
@@ -217,21 +216,21 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(char[] array, char value) {
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (value > array[mid]) {
- low = mid + 1;
- } else if (value == array[mid]) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- if (mid < 0) {
- return -1;
- }
- return -mid - (value < array[mid] ? 1 : 2);
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ char midVal = array[mid];
+
+ if (midVal < value)
+ lo = mid + 1;
+ else if (midVal > value)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
}
/**
@@ -248,22 +247,32 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(double[] array, double value) {
- long longBits = Double.doubleToLongBits(value);
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (lessThan(array[mid], value)) {
- low = mid + 1;
- } else if (longBits == Double.doubleToLongBits(array[mid])) {
- return mid;
- } else {
- high = mid - 1;
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ double midVal = array[mid];
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else if (midVal != 0 && midVal == value) {
+ return mid; // value found
+ } else { // Either midVal and value are == 0 or at least one is NaN
+ long midValBits = Double.doubleToLongBits(midVal);
+ long valueBits = Double.doubleToLongBits(value);
+
+ if (midValBits < valueBits)
+ lo = mid + 1; // (-0.0, 0.0) or (not NaN, NaN); midVal < val
+ else if (midValBits > valueBits)
+ hi = mid - 1; // (0.0, -0.0) or (NaN, not NaN); midVal > val
+ else
+ return mid; // bit patterns are equal; value found
}
}
- if (mid < 0) {
- return -1;
- }
- return -mid - (lessThan(value, array[mid]) ? 1 : 2);
+ return ~lo; // value not present
}
/**
@@ -280,22 +289,32 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(float[] array, float value) {
- int intBits = Float.floatToIntBits(value);
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (lessThan(array[mid], value)) {
- low = mid + 1;
- } else if (intBits == Float.floatToIntBits(array[mid])) {
- return mid;
- } else {
- high = mid - 1;
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ float midVal = array[mid];
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else if (midVal != 0 && midVal == value) {
+ return mid; // value found
+ } else { // Either midVal and value are == 0 or at least one is NaN
+ int midValBits = Float.floatToIntBits(midVal);
+ int valueBits = Float.floatToIntBits(value);
+
+ if (midValBits < valueBits)
+ lo = mid + 1; // (-0.0, 0.0) or (not NaN, NaN); midVal < val
+ else if (midValBits > valueBits)
+ hi = mid - 1; // (0.0, -0.0) or (NaN, not NaN); midVal > val
+ else
+ return mid; // bit patterns are equal; value found
}
}
- if (mid < 0) {
- return -1;
- }
- return -mid - (lessThan(value, array[mid]) ? 1 : 2);
+ return ~lo; // value not present
}
/**
@@ -311,23 +330,23 @@
* @return the non-negative index of the element, or a negative index which
* is {@code -index - 1} where the element would be inserted.
*/
- public static int binarySearch(int[] array, int value) {
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (value > array[mid]) {
- low = mid + 1;
- } else if (value == array[mid]) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- if (mid < 0) {
- return -1;
- }
- return -mid - (value < array[mid] ? 1 : 2);
- }
+ public static int binarySearch(int[] array, int value) {
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ int midVal = array[mid];
+
+ if (midVal < value)
+ lo = mid + 1;
+ else if (midVal > value)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
+ }
/**
* Performs a binary search for the specified element in the specified
@@ -343,21 +362,21 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(long[] array, long value) {
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (value > array[mid]) {
- low = mid + 1;
- } else if (value == array[mid]) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- if (mid < 0) {
- return -1;
- }
- return -mid - (value < array[mid] ? 1 : 2);
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ long midVal = array[mid];
+
+ if (midVal < value)
+ lo = mid + 1;
+ else if (midVal > value)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
}
/**
@@ -368,7 +387,7 @@
*
* @param array
* the sorted {@code Object} array to search.
- * @param object
+ * @param value
* the {@code Object} element to find.
* @return the non-negative index of the element, or a negative index which
* is {@code -index - 1} where the element would be inserted.
@@ -376,24 +395,23 @@
* if an element in the array or the search element does not
* implement {@code Comparable}, or cannot be compared to each other.
*/
- @SuppressWarnings("unchecked")
- public static int binarySearch(Object[] array, Object object) {
- if (array.length == 0) {
- return -1;
- }
+ public static int binarySearch(Object[] array, Object value) {
+ int lo = 0;
+ int hi = array.length - 1;
- int low = 0, mid = 0, high = array.length - 1, result = 0;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if ((result = ((Comparable<Object>)array[mid]).compareTo(object)) < 0){
- low = mid + 1;
- } else if (result == 0) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- return -mid - (result >= 0 ? 1 : 2);
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ @SuppressWarnings("unchecked")
+ int midValCmp = ((Comparable) array[mid]).compareTo(value);
+
+ if (midValCmp < 0)
+ lo = mid + 1;
+ else if (midValCmp > 0)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
}
/**
@@ -405,7 +423,7 @@
*
* @param array
* the sorted array to search
- * @param object
+ * @param value
* the element to find
* @param comparator
* the {@code Comparator} sued to compare the elements.
@@ -415,24 +433,26 @@
* if an element in the array cannot be compared to the search element
* using the {@code Comparator}.
*/
- public static <T> int binarySearch(T[] array, T object,
+ public static <T> int binarySearch(T[] array, T value,
Comparator<? super T> comparator) {
- if (comparator == null) {
- return binarySearch(array, object);
- }
+ if (comparator == null)
+ return binarySearch(array, value);
- int low = 0, mid = 0, high = array.length - 1, result = 0;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if ((result = comparator.compare(array[mid], object)) < 0) {
- low = mid + 1;
- } else if (result == 0) {
- return mid;
- } else {
- high = mid - 1;
- }
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ int midValCmp = comparator.compare(array[mid], value);
+
+ if (midValCmp < 0)
+ lo = mid + 1;
+ else if (midValCmp > 0)
+ hi = mid - 1;
+ else
+ return mid; // value found
}
- return -mid - (result >= 0 ? 1 : 2);
+ return ~lo; // value not present
}
/**
@@ -449,21 +469,21 @@
* is {@code -index - 1} where the element would be inserted.
*/
public static int binarySearch(short[] array, short value) {
- int low = 0, mid = -1, high = array.length - 1;
- while (low <= high) {
- mid = (low + high) >>> 1;
- if (value > array[mid]) {
- low = mid + 1;
- } else if (value == array[mid]) {
- return mid;
- } else {
- high = mid - 1;
- }
- }
- if (mid < 0) {
- return -1;
- }
- return -mid - (value < array[mid] ? 1 : 2);
+ int lo = 0;
+ int hi = array.length - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ short midVal = array[mid];
+
+ if (midVal < value)
+ lo = mid + 1;
+ else if (midVal > value)
+ hi = mid - 1;
+ else
+ return mid; // value found
+ }
+ return ~lo; // value not present
}
/**
@@ -1501,103 +1521,6 @@
return equals((short[]) e1, (short[]) e2);
}
- private static boolean lessThan(double double1, double double2) {
- // A slightly specialized version of
- // Double.compare(double1, double2) < 0.
-
- // Non-zero and non-NaN checking.
- if (double1 < double2) {
- return true;
- }
- if (double1 > double2) {
- return false;
- }
- if (double1 == double2 && 0.0d != double1) {
- return false;
- }
-
- // NaNs are equal to other NaNs and larger than any other double.
- if (Double.isNaN(double1)) {
- return false;
- } else if (Double.isNaN(double2)) {
- return true;
- }
-
- // Deal with +0.0 and -0.0.
- long d1 = Double.doubleToRawLongBits(double1);
- long d2 = Double.doubleToRawLongBits(double2);
- return d1 < d2;
- }
-
- private static boolean lessThan(float float1, float float2) {
- // A slightly specialized version of Float.compare(float1, float2) < 0.
-
- // Non-zero and non-NaN checking.
- if (float1 < float2) {
- return true;
- }
- if (float1 > float2) {
- return false;
- }
- if (float1 == float2 && 0.0f != float1) {
- return false;
- }
-
- // NaNs are equal to other NaNs and larger than any other float
- if (Float.isNaN(float1)) {
- return false;
- } else if (Float.isNaN(float2)) {
- return true;
- }
-
- // Deal with +0.0 and -0.0
- int f1 = Float.floatToRawIntBits(float1);
- int f2 = Float.floatToRawIntBits(float2);
- return f1 < f2;
- }
-
- private static int med3(byte[] array, int a, int b, int c) {
- byte x = array[a], y = array[b], z = array[c];
- return x < y ? (y < z ? b : (x < z ? c : a)) : (y > z ? b : (x > z ? c
- : a));
- }
-
- private static int med3(char[] array, int a, int b, int c) {
- char x = array[a], y = array[b], z = array[c];
- return x < y ? (y < z ? b : (x < z ? c : a)) : (y > z ? b : (x > z ? c
- : a));
- }
-
- private static int med3(double[] array, int a, int b, int c) {
- double x = array[a], y = array[b], z = array[c];
- return lessThan(x, y) ? (lessThan(y, z) ? b : (lessThan(x, z) ? c : a))
- : (lessThan(z, y) ? b : (lessThan(z, x) ? c : a));
- }
-
- private static int med3(float[] array, int a, int b, int c) {
- float x = array[a], y = array[b], z = array[c];
- return lessThan(x, y) ? (lessThan(y, z) ? b : (lessThan(x, z) ? c : a))
- : (lessThan(z, y) ? b : (lessThan(z, x) ? c : a));
- }
-
- private static int med3(int[] array, int a, int b, int c) {
- int x = array[a], y = array[b], z = array[c];
- return x < y ? (y < z ? b : (x < z ? c : a)) : (y > z ? b : (x > z ? c
- : a));
- }
-
- private static int med3(long[] array, int a, int b, int c) {
- long x = array[a], y = array[b], z = array[c];
- return x < y ? (y < z ? b : (x < z ? c : a)) : (y > z ? b : (x > z ? c
- : a));
- }
-
- private static int med3(short[] array, int a, int b, int c) {
- short x = array[a], y = array[b], z = array[c];
- return x < y ? (y < z ? b : (x < z ? c : a)) : (y > z ? b : (x > z ? c
- : a));
- }
-
/**
* Sorts the specified array in ascending numerical order.
*
@@ -1630,7 +1553,7 @@
if (start > end) {
// K0033=Start index ({0}) is greater than end index ({1})
throw new IllegalArgumentException(Msg.getString("K0033", //$NON-NLS-1$
- Integer.valueOf(start), Integer.valueOf(end)));
+ start, end));
}
if (start < 0) {
// K0052=Array index out of range\: {0}