From 66170487efac01381b97cda847c4a381a8c731ab Mon Sep 17 00:00:00 2001 From: gmungoc Date: Tue, 10 Jan 2017 14:38:48 +0000 Subject: [PATCH] JAL-2377 avoid infinite loop formatting 1.0E-310 --- src/jalview/util/Format.java | 6 +--- test/jalview/util/FormatTest.java | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/jalview/util/Format.java b/src/jalview/util/Format.java index 389afcd..bf52027 100755 --- a/src/jalview/util/Format.java +++ b/src/jalview/util/Format.java @@ -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')) { diff --git a/test/jalview/util/FormatTest.java b/test/jalview/util/FormatTest.java index 1404f0b..999e456 100644 --- a/test/jalview/util/FormatTest.java +++ b/test/jalview/util/FormatTest.java @@ -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); + } } -- 1.7.10.2