JAL-2377 avoid infinite loop formatting 1.0E-310
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 10 Jan 2017 14:38:48 +0000 (14:38 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 10 Jan 2017 14:38:48 +0000 (14:38 +0000)
src/jalview/util/Format.java
test/jalview/util/FormatTest.java

index 389afcd..bf52027 100755 (executable)
@@ -884,21 +884,18 @@ public class Format
     String f = "";
     int e = 0;
     double dd = d;
-    double factor = 1;
 
     if (d != 0)
     {
       while (dd > 10)
       {
         e++;
-        factor /= 10;
         dd = dd / 10;
       }
 
       while (dd < 1)
       {
         e--;
-        factor *= 10;
         dd = dd * 10;
       }
     }
@@ -908,8 +905,7 @@ public class Format
       return fixed_format(d);
     }
 
-    d = d * factor;
-    f = f + fixed_format(d);
+    f = f + fixed_format(dd);
 
     if ((fmt == 'e') || (fmt == 'g'))
     {
index 1404f0b..999e456 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.util;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 import jalview.gui.JvOptionPane;
 
@@ -96,4 +97,69 @@ public class FormatTest
     assertEquals(Format.repeat('b', 0), "");
     assertEquals(Format.repeat('c', -1), "");
   }
+
+  @Test(groups = "Functional")
+  public void testFormat_scientific()
+  {
+    Format f = new Format("%3.4e");
+    double d = 1d;
+    assertEquals(f.form(d), "1.0000e+000");
+    assertEquals(String.format("%3.4e", d), "1.0000e+00");
+
+    d = 12345678.12345678d;
+    assertEquals(f.form(d), "1.2346e+007");
+    assertEquals(String.format("%3.4e", d), "1.2346e+07");
+  }
+
+  /**
+   * Test that fails (in 2.10.1) with timeout as there is an infinite loop in
+   * Format.exp_format()
+   */
+  @Test(groups = "Functional", timeOut = 500)
+  public void testFormat_scientific_overflow()
+  {
+    Format f = new Format("%3.4e");
+    double d = 1.12E-310;
+    /*
+     * problem: exp_format() scales up 'd' to the range 1-10
+     * while computing a scaling factor, but this factor acquires
+     * the value Double.POSITIVE_INFINITY instead of 1.0E+309
+     * the value to be formatted is multipled by factor and becomes Infinity
+     * resulting in an infinite loop in the recursive call to exp_format()
+     */
+    assertEquals(f.form(d), "1.1200e-310");
+  }
+
+  /**
+   * This test shows that Format.form() is faster for this case than
+   * String.format()
+   */
+  @Test(groups = "Timing")
+  public void testFormat_scientificTiming()
+  {
+    Format f = new Format("%3.4e");
+    double d = 12345678.12345678d;
+
+    int iterations = 1000;
+    long start = System.currentTimeMillis();
+    for (int i = 0; i < iterations; i++)
+    {
+      f.form(d);
+    }
+    long stop = System.currentTimeMillis();
+    long elapsed1 = stop - start;
+    System.out.println(iterations + " x Format.form took " + elapsed1
+            + "ms");
+
+    start = System.currentTimeMillis();
+    for (int i = 0; i < iterations; i++)
+    {
+      String.format("%3.4e", d);
+    }
+    stop = System.currentTimeMillis();
+    long elapsed2 = stop - start;
+    System.out.println(iterations + " x String.format took " + elapsed2
+            + "ms");
+    assertTrue(elapsed2 > elapsed1);
+  }
 }