private static void doSelect()

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;
                    }
                }
            }
        }
    }