Author: luc Date: Mon Aug 15 20:31:49 2011 New Revision: 1157994 URL: http://svn.apache.org/viewvc?rev=1157994&view=rev Log: Fixed handling of Infinite and NaN coefficients in linearCombination
Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java?rev=1157994&r1=1157993&r2=1157994&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java Mon Aug 15 20:31:49 2011 @@ -2402,7 +2402,15 @@ public final class MathUtils { // final rounding, s12 may have suffered many cancellations, we try // to recover some bits from the extra words we have saved up to now - return s12High + (prod1Low + prod2Low + s12Low); + double result = s12High + (prod1Low + prod2Low + s12Low); + + if (Double.isNaN(result)) { + // either we have split infinite numbers or some coefficients were NaNs, + // just rely on the naive implementation and let IEEE754 handle this + result = a1 * b1 + a2 * b2; + } + + return result; } @@ -2492,7 +2500,15 @@ public final class MathUtils { // final rounding, s123 may have suffered many cancellations, we try // to recover some bits from the extra words we have saved up to now - return s123High + (prod1Low + prod2Low + prod3Low + s12Low + s123Low); + double result = s123High + (prod1Low + prod2Low + prod3Low + s12Low + s123Low); + + if (Double.isNaN(result)) { + // either we have split infinite numbers or some coefficients were NaNs, + // just rely on the naive implementation and let IEEE754 handle this + result = a1 * b1 + a2 * b2 + a3 * b3; + } + + return result; } @@ -2604,7 +2620,15 @@ public final class MathUtils { // final rounding, s1234 may have suffered many cancellations, we try // to recover some bits from the extra words we have saved up to now - return s1234High + (prod1Low + prod2Low + prod3Low + prod4Low + s12Low + s123Low + s1234Low); + double result = s1234High + (prod1Low + prod2Low + prod3Low + prod4Low + s12Low + s123Low + s1234Low); + + if (Double.isNaN(result)) { + // either we have split infinite numbers or some coefficients were NaNs, + // just rely on the naive implementation and let IEEE754 handle this + result = a1 * b1 + a2 * b2 + a3 * b3 + a4 * b4; + } + + return result; } @@ -2667,6 +2691,19 @@ public final class MathUtils { sHighPrev = sHighCur; } - return sHighPrev + (prodLowSum + sLowSum); + double result = sHighPrev + (prodLowSum + sLowSum); + + if (Double.isNaN(result)) { + // either we have split infinite numbers or some coefficients were NaNs, + // just rely on the naive implementation and let IEEE754 handle this + result = 0; + for (int i = 0; i < len; ++i) { + result += a[i] * b[i]; + } + } + + return result; + } + } Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java?rev=1157994&r1=1157993&r2=1157994&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java (original) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java Mon Aug 15 20:31:49 2011 @@ -1885,4 +1885,158 @@ public final class MathUtilsTest { Assert.assertEquals(sInline, sArray, 0); } } + + @Test + public void testLinearCombinationInfinite() { + final double[][] a = new double[][] { + { 1, 2, 3, 4}, + { 1, Double.POSITIVE_INFINITY, 3, 4}, + { 1, 2, Double.POSITIVE_INFINITY, 4}, + { 1, Double.POSITIVE_INFINITY, 3, Double.NEGATIVE_INFINITY}, + { 1, 2, 3, 4}, + { 1, 2, 3, 4}, + { 1, 2, 3, 4}, + { 1, 2, 3, 4} + }; + final double[][] b = new double[][] { + { 1, -2, 3, 4}, + { 1, -2, 3, 4}, + { 1, -2, 3, 4}, + { 1, -2, 3, 4}, + { 1, Double.POSITIVE_INFINITY, 3, 4}, + { 1, -2, Double.POSITIVE_INFINITY, 4}, + { 1, Double.POSITIVE_INFINITY, 3, Double.NEGATIVE_INFINITY}, + { Double.NaN, -2, 3, 4} + }; + + Assert.assertEquals(-3, + MathUtils.linearCombination(a[0][0], b[0][0], + a[0][1], b[0][1]), + 1.0e-10); + Assert.assertEquals(6, + MathUtils.linearCombination(a[0][0], b[0][0], + a[0][1], b[0][1], + a[0][2], b[0][2]), + 1.0e-10); + Assert.assertEquals(22, + MathUtils.linearCombination(a[0][0], b[0][0], + a[0][1], b[0][1], + a[0][2], b[0][2], + a[0][3], b[0][3]), + 1.0e-10); + Assert.assertEquals(22, MathUtils.linearCombination(a[0], b[0]), 1.0e-10); + + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[1][0], b[1][0], + a[1][1], b[1][1]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[1][0], b[1][0], + a[1][1], b[1][1], + a[1][2], b[1][2]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[1][0], b[1][0], + a[1][1], b[1][1], + a[1][2], b[1][2], + a[1][3], b[1][3]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, MathUtils.linearCombination(a[1], b[1]), 1.0e-10); + + Assert.assertEquals(-3, + MathUtils.linearCombination(a[2][0], b[2][0], + a[2][1], b[2][1]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[2][0], b[2][0], + a[2][1], b[2][1], + a[2][2], b[2][2]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[2][0], b[2][0], + a[2][1], b[2][1], + a[2][2], b[2][2], + a[2][3], b[2][3]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, MathUtils.linearCombination(a[2], b[2]), 1.0e-10); + + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[3][0], b[3][0], + a[3][1], b[3][1]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[3][0], b[3][0], + a[3][1], b[3][1], + a[3][2], b[3][2]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, + MathUtils.linearCombination(a[3][0], b[3][0], + a[3][1], b[3][1], + a[3][2], b[3][2], + a[3][3], b[3][3]), + 1.0e-10); + Assert.assertEquals(Double.NEGATIVE_INFINITY, MathUtils.linearCombination(a[3], b[3]), 1.0e-10); + + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[4][0], b[4][0], + a[4][1], b[4][1]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[4][0], b[4][0], + a[4][1], b[4][1], + a[4][2], b[4][2]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[4][0], b[4][0], + a[4][1], b[4][1], + a[4][2], b[4][2], + a[4][3], b[4][3]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, MathUtils.linearCombination(a[4], b[4]), 1.0e-10); + + Assert.assertEquals(-3, + MathUtils.linearCombination(a[5][0], b[5][0], + a[5][1], b[5][1]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[5][0], b[5][0], + a[5][1], b[5][1], + a[5][2], b[5][2]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[5][0], b[5][0], + a[5][1], b[5][1], + a[5][2], b[5][2], + a[5][3], b[5][3]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, MathUtils.linearCombination(a[5], b[5]), 1.0e-10); + + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[6][0], b[6][0], + a[6][1], b[6][1]), + 1.0e-10); + Assert.assertEquals(Double.POSITIVE_INFINITY, + MathUtils.linearCombination(a[6][0], b[6][0], + a[6][1], b[6][1], + a[6][2], b[6][2]), + 1.0e-10); + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[6][0], b[6][0], + a[6][1], b[6][1], + a[6][2], b[6][2], + a[6][3], b[6][3]))); + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[6], b[6]))); + + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[7][0], b[7][0], + a[7][1], b[7][1]))); + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[7][0], b[7][0], + a[7][1], b[7][1], + a[7][2], b[7][2]))); + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[7][0], b[7][0], + a[7][1], b[7][1], + a[7][2], b[7][2], + a[7][3], b[7][3]))); + Assert.assertTrue(Double.isNaN(MathUtils.linearCombination(a[7], b[7]))); + + } + }