diff -r -u old\DualPivotQuicksort.java new\DualPivotQuicksort.java --- old\DualPivotQuicksort.java Mon May 17 10:16:20 2010 +++ new\DualPivotQuicksort.java Mon May 17 15:55:15 2010 @@ -1675,20 +1675,13 @@ */ private static void sortNegZeroAndNaN(float[] a, int left, int right) { /* - * Phase 1: Count negative zeros, turn them into positive zeros, - * and move NaNs to end of array. + * Phase 1: Move NaNs to end of array. */ - final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); - int numNegativeZeros = 0; - for (int k = left; k <= right; k++) { float ak = a[k]; - if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) { - a[k] = 0.0f; - numNegativeZeros++; - } else if (ak != ak) { // i.e., ak is NaN + if (ak != ak) { // i.e., ak is NaN a[k--] = a[right]; - a[right--] = Float.NaN; + a[right--] = ak; } } @@ -1698,15 +1691,61 @@ sort(a, left, right, true); /* - * Phase 3: Turn positive zeros back into negative zeros. + * Phase 3: Place negative zeros before positive zeros. */ - if (numNegativeZeros == 0) { + processZeros(a, left, right); + } + + private static void processZeros(float[] a, int low, int high) { + if (high - low < 1) return; // there should be at least 2 elements + + int numNegativeZeros; + int zeroIndex; + float al = a[low]; + if (al < 0.0f) { + float ah = a[high]; + if (ah > 0.0f) { // the most common case + // exclude a[low] and a[high] because they are not zeros definitely + zeroIndex = findFirstZero(a, low + 1, high - 1); + // skip leading negative zeros, they are just on their places + while (Float.floatToRawIntBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex); + } else if (ah == 0.0f) { + // scan backward + // count negative zeros and turn them into positive + zeroIndex = high; + numNegativeZeros = 0; + for (; a[zeroIndex] == 0.0f; --zeroIndex) { + if (Float.floatToRawIntBits(a[zeroIndex]) < 0) { + a[zeroIndex] = +0.0f; + ++numNegativeZeros; + } + } + ++zeroIndex; + } else { // a[high] < 0.0f, a[high] cannot be NaN + // nothing to do + return; + } + } else if (al == 0.0f) { + zeroIndex = low; + if (a[high] > 0.0f) { + // skip leading negative zeros + while (Float.floatToRawIntBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex); + } else { // a[high] == 0.0f, a[high] cannot be NaN and negative + // full scan + // skip leading negative zeros + while (zeroIndex <= high && Float.floatToRawIntBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex, high); + } + } else { // a[low] > 0.0f, a[low] cannot be NaN + // nothing to do return; } - // Find first zero element - int zeroIndex = findFirstZero(a, left, right); - // Turn the right number of positive zeros back into negative zeros for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { a[i] = -0.0f; @@ -1736,6 +1775,28 @@ return low; } + private static int countNegativeZerosAndMakeThemPositive(float[] a, int i) { + int numNegativeZeros = 0; + for(; a[i] == 0.0f; ++i) { + if (Float.floatToRawIntBits(a[i]) < 0) { // negative zero + a[i] = +0.0f; + ++numNegativeZeros; + } + } + return numNegativeZeros; + } + + private static int countNegativeZerosAndMakeThemPositive(float[] a, int i, int high) { + int numNegativeZeros = 0; + for(; i <= high; ++i) { + if (Float.floatToRawIntBits(a[i]) < 0) { // negative zero + a[i] = +0.0f; + ++numNegativeZeros; + } + } + return numNegativeZeros; + } + /** * Sorts the specified range of the array into ascending order by the * Dual-Pivot Quicksort algorithm. This method differs from the public @@ -2062,20 +2123,13 @@ */ private static void sortNegZeroAndNaN(double[] a, int left, int right) { /* - * Phase 1: Count negative zeros, turn them into positive zeros, - * and move NaNs to end of array. + * Phase 1: Move NaNs to end of array. */ - final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); - int numNegativeZeros = 0; - for (int k = left; k <= right; k++) { double ak = a[k]; - if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) { - a[k] = 0.0d; - numNegativeZeros++; - } else if (ak != ak) { // i.e., ak is NaN + if (ak != ak) { // i.e., ak is NaN a[k--] = a[right]; - a[right--] = Double.NaN; + a[right--] = ak; // or Double.NaN } } @@ -2085,15 +2139,60 @@ sort(a, left, right, true); /* - * Phase 3: Turn positive zeros back into negative zeros. + * Phase 3: Place negative zeros before positive zeros. */ - if (numNegativeZeros == 0) { + processZeros(a, left, right); + } + + private static void processZeros(double[] a, int low, int high) { + if (high - low < 1) return; // there should be at least 2 elements + + int numNegativeZeros; + int zeroIndex; + double al = a[low]; + if (al < 0.0d) { + double ah = a[high]; + if (ah > 0.0d) { // the most common case + zeroIndex = findFirstZero(a, low + 1, high - 1); // exclude a[low] and a[high] because they are not zeros + // skip leading negative zeros + while (Double.doubleToRawLongBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex); + } else if (ah == 0.0d) { + // scan backward + // count negative zeros and turn them into positive + zeroIndex = high; + numNegativeZeros = 0; + for (; a[zeroIndex] == 0.0d; --zeroIndex) { + if (Double.doubleToRawLongBits(a[zeroIndex]) < 0) { + a[zeroIndex] = +0.0d; + ++numNegativeZeros; + } + } + ++zeroIndex; + } else { // a[high] < 0.0d, a[high] cannot be NaN + // nothing to do + return; + } + } else if (al == 0.0d) { + zeroIndex = low; + if (a[high] > 0.0d) { + // skip leading negative zeros + while (Double.doubleToRawLongBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex); + } else { // a[high] == 0.0d, a[high] cannot be NaN and negative + // full scan + // skip leading negative zeros + while (zeroIndex <= high && Double.doubleToRawLongBits(a[zeroIndex]) < 0) ++zeroIndex; + // count negative zeros and turn them into positive + numNegativeZeros = countNegativeZerosAndMakeThemPositive(a, zeroIndex, high); + } + } else { // a[low] > 0.0d, a[low] cannot be NaN + // nothing to do return; } - // Find first zero element - int zeroIndex = findFirstZero(a, left, right); - // Turn the right number of positive zeros back into negative zeros for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { a[i] = -0.0d; @@ -2121,6 +2220,28 @@ } } return low; + } + + private static int countNegativeZerosAndMakeThemPositive(double[] a, int i) { + int numNegativeZeros = 0; + for(; a[i] == 0.0d; ++i) { + if (Double.doubleToRawLongBits(a[i]) < 0) { // negative zero + a[i] = +0.0d; + ++numNegativeZeros; + } + } + return numNegativeZeros; + } + + private static int countNegativeZerosAndMakeThemPositive(double[] a, int i, int high) { + int numNegativeZeros = 0; + for(; i <= high; ++i) { + if (Double.doubleToRawLongBits(a[i]) < 0) { // negative zero + a[i] = +0.0d; + ++numNegativeZeros; + } + } + return numNegativeZeros; } /**