Ian Rogers wrote: > The 1st thing is that comparing floats for less-than or greater-than > won't return true if one of the values is NaN, so it's easy to > dispatch those most common cases first (and also avoid any float to > int conversions which are painful as you need to shuffle float > registers to integer ones and do NaN tests).
Ok, so that is a simple (float1 > float2) and (float2 > float1) check. > Next doing a comparison > of raw int bits (avoiding a NaN test if using floatToIntBits) will > cover the case of equality without returning true for -0.0 and 0.0. So if the *raw* int bits (call them f1 and f2) are == then return 0. > Following these 2 cases we either have values that are NaN or > 0.0/-0.0. Float/Double isNaN has a fast test for NaN that uses a > single floating point compare, so both parameters need testing to see > if they are NaN and if they are a result created (the javadoc > specifies this). // NaNs are equal to other NaNs and larger than any other float if (isNaN(float1)) { if (isNaN(float2)) { return 0; } return 1; } else if (isNaN(float2)) { return -1; } > Finally we can recycle the raw int bit representation > and realize that we either have 0x80000000 or 0x00000000 for -0.0 and > 0.0 (add more 0s for doubles). Therefore an integer comparison will > return their ordering (the current code in Float.compare uses this > trick). (f1 < f2) ? -1 : 1; > Compared to the current code (in Float) and counting comparisons > (where the conversion of floatToIntBits requires an additional > floating-point comparison to detect NaN): > - If the 2 parameters are regular (ie not NaN) non-equal floating > point values - upto 2 floating point comparisons are necessary, the > current code needs 2 integer and 4 floating point comparisons > - If the 2 parameters are equal but not 0.0 and -0.0 - 2 floating > point comparisons and 1 integer comparison are necessary, the current > code needs 3 integer and 3 floating point comparisons > - If 1 or both of the parameters are NaN then - 4 floating point > comparisons and 1 integer comparison are necessary, the current code > needs 2 integer and 2 floating point comparisons (the current code is > probably faster but this case is unlikely) > - If the parameters are 0.0 and -0.0 then - 4 floating point > comparisons and 2 integer comparison are necessary, the current code > needs 3 integer and 4 floating point comparisons > > The main thing is the common case where 2 integer and 2 floating point > comparisons are saved (and this is frequently executed code if sorting > an array). For equality then 1 floating point compare and 2 integer > compares are saved, or in the case of 0.0 and -0.0 (or vice versa) 1 > integer comparison is saved. The code is probably slower when there > are NaNs, but I believe this case is uncommon. Cool, take a look at the new version and see if you agree with the changes: Index: modules/luni/src/main/java/java/lang/Float.java =================================================================== --- modules/luni/src/main/java/java/lang/Float.java (revision 770260) +++ modules/luni/src/main/java/java/lang/Float.java (working copy) @@ -145,25 +145,7 @@ * @since 1.2 */ public int compareTo(Float object) { - int f1, f2; - int NaNbits = Float.floatToIntBits(Float.NaN); - if ((f1 = Float.floatToIntBits(value)) == NaNbits) { - if (Float.floatToIntBits(object.value) == NaNbits) { - return 0; - } - return 1; - } - if ((f2 = Float.floatToIntBits(object.value)) == NaNbits) { - return -1; - } - if (value == object.value) { - if (f1 == f2) { - return 0; - } - // check for -0 - return f1 > f2 ? 1 : -1; - } - return value > object.value ? 1 : -1; + return compare(value, object.value); } /** @@ -402,25 +384,31 @@ * @since 1.4 */ public static int compare(float float1, float float2) { - int f1, f2; - int NaNbits = Float.floatToIntBits(Float.NaN); - if ((f1 = Float.floatToIntBits(float1)) == NaNbits) { - if (Float.floatToIntBits(float2) == NaNbits) { - return 0; - } + + if (float1 > float2) { return 1; } - if ((f2 = Float.floatToIntBits(float2)) == NaNbits) { + if (float2 > float1) { return -1; } - if (float1 == float2) { - if (f1 == f2) { + + int f1 = floatToRawIntBits(float1); + int f2 = floatToRawIntBits(float2); + if (f1 == f2) { + return 0; + } + + // NaNs are equal to other NaNs and larger than any other float + if (isNaN(float1)) { + if (isNaN(float2)) { return 0; } - // check for -0 - return f1 > f2 ? 1 : -1; + return 1; + } else if (isNaN(float2)) { + return -1; } - return float1 > float2 ? 1 : -1; + + return (f1 < f2) ? -1 : 1; } /**