harmony-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tim Ellison <t.p.elli...@gmail.com>
Subject Re: Float/Double comparison performance
Date Thu, 30 Apr 2009 21:17:44 GMT
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;
     }

     /**

Mime
View raw message