This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
The following commit(s) were added to refs/heads/master by this push: new 8bd0aba6 NUMBERS-200: Don't honour compensation if it's NaN in Sum#add (#136) 8bd0aba6 is described below commit 8bd0aba6b031daed1d00de6805c1639fffe7f3d0 Author: Anirudh <129569933+ani5r...@users.noreply.github.com> AuthorDate: Sun Jul 23 00:05:23 2023 +0530 NUMBERS-200: Don't honour compensation if it's NaN in Sum#add (#136) --- .../java/org/apache/commons/numbers/core/Sum.java | 8 ++++++- .../org/apache/commons/numbers/core/SumTest.java | 28 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Sum.java b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Sum.java index 05ebecfe..6aaff723 100644 --- a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Sum.java +++ b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Sum.java @@ -202,7 +202,13 @@ public final class Sum * @return this instance. */ private Sum add(double s, double c) { - return add(s).add(c); + add(s); + // compensation can be NaN from accumulating one or more same-signed infinite values. + // Do not pollute the regular IEEE754 sum with a spurious NaN. + if (!Double.isNaN(c)) { + add(c); + } + return this; } /** diff --git a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/SumTest.java b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/SumTest.java index 5e42a727..844d7096 100644 --- a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/SumTest.java +++ b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/SumTest.java @@ -19,9 +19,13 @@ package org.apache.commons.numbers.core; import java.math.BigDecimal; import java.math.MathContext; import java.util.Arrays; +import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class SumTest { @@ -49,6 +53,30 @@ class SumTest { assertSum(Double.NEGATIVE_INFINITY, 1, Double.NEGATIVE_INFINITY, 1); } + @ParameterizedTest + @MethodSource(value = "testAddInstance") + void testAddInstance(double[][] values, double expected) { + Sum sum1 = Sum.create().add(values[0]); + Sum sum2 = Sum.create().add(values[1]); + sum1.add(sum2); + Assertions.assertEquals(expected, sum1.getAsDouble()); + } + + static Stream<Arguments> testAddInstance() { + return Stream.of( + Arguments.of(new double[][] {{Double.POSITIVE_INFINITY}, {Double.POSITIVE_INFINITY}}, + Double.POSITIVE_INFINITY), + Arguments.of(new double[][] {{1, 2, -3}, {3, -1, -2}}, 0), + Arguments.of(new double[][] {{1, 2, 3}, {4, 5, -6}}, 9), + Arguments.of(new double[][] {{3.1415, 2.718}, {1000, 0.001}}, + 1005.8605), + Arguments.of(new double[][] {{1729, 2520}, {Double.MAX_VALUE, Double.MAX_VALUE}}, + Double.POSITIVE_INFINITY), + Arguments.of(new double[][] {{Double.NEGATIVE_INFINITY, 85}, {-1, -7, -2, -9}}, + Double.NEGATIVE_INFINITY) + ); + } + @Test void testSumAccuracy() { // arrange