in commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Selection.java [256:333]
private static void doSelect(double[] a, int fromIndex, int toIndex, int[] k) {
if (k.length == 0 || toIndex - fromIndex <= 1) {
return;
}
// Sort NaN / count signed zeros.
// Caution: This loop contributes significantly to the runtime for single indices.
int cn = 0;
int end = toIndex;
for (int i = toIndex; --i >= fromIndex;) {
final double v = a[i];
// Count negative zeros using a sign bit check
if (Double.doubleToRawLongBits(v) == Long.MIN_VALUE) {
cn++;
// Change to positive zero.
// Data must be repaired after selection.
a[i] = 0.0;
} else if (v != v) {
// Move NaN to end
a[i] = a[--end];
a[end] = v;
}
}
// Partition
int n = 0;
if (end - fromIndex > 1) {
n = k.length;
// Filter indices invalidated by NaN check
if (end < toIndex) {
for (int i = n; --i >= 0;) {
final int index = k[i];
if (index >= end) {
// Move to end
k[i] = k[--n];
k[n] = index;
}
}
}
// Return n, the count of used indices in k.
// Use this to post-process zeros.
n = QuickSelect.select(a, fromIndex, end - 1, k, n);
}
// Restore signed zeros
if (cn != 0) {
// Use partition indices below zero to fast-forward to zero as much as possible
int j = -1;
if (n < 0) {
// Binary search on -n sorted indices: hi = (-n) - 1
int lo = 0;
int hi = ~n;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
if (a[k[mid]] < 0) {
j = mid;
lo = mid + 1;
} else {
hi = mid - 1;
}
}
} else {
// Unsorted, process all indices
for (int i = n; --i >= 0;) {
if (a[k[i]] < 0) {
j = k[i];
}
}
}
for (;;) {
if (a[++j] == 0) {
a[j] = -0.0;
if (--cn == 0) {
break;
}
}
}
}
}