From 3f7de0eb1e50546144004e3449be0978b68a2a5d Mon Sep 17 00:00:00 2001 From: Alex Herbert Date: Sat, 21 Aug 2021 09:11:05 +0100 Subject: [PATCH] sonar fix: Handle variance=0 in skewness computation for input array --- .../stat/descriptive/moment/Skewness.java | 30 +++++++++++-------- .../stat/descriptive/moment/SkewnessTest.java | 5 ++++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java index 3e7fa53fc..05eb18908 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java @@ -49,6 +49,9 @@ public class Skewness extends AbstractStorelessUnivariateStatistic implements Se /** Serializable version identifier. */ private static final long serialVersionUID = 20150412L; + /** The value below which the variance is considered zero and thus skewness is zero. */ + private static final double ZERO_VARIANCE_THRESHOLD = 10E-20; + /** Third moment on which this statistic is based. */ protected ThirdMoment moment; @@ -115,7 +118,7 @@ public class Skewness extends AbstractStorelessUnivariateStatistic implements Se return Double.NaN; } double variance = moment.m2 / (moment.n - 1); - if (variance < 10E-20) { + if (variance < ZERO_VARIANCE_THRESHOLD) { return 0.0d; } else { double n0 = moment.getN(); @@ -180,19 +183,22 @@ public class Skewness extends AbstractStorelessUnivariateStatistic implements Se accum2 += d; } final double variance = (accum - (accum2 * accum2 / length)) / (length - 1); + if (variance < ZERO_VARIANCE_THRESHOLD) { + skew = 0.0d; + } else { + double accum3 = 0.0; + for (int i = begin; i < begin + length; i++) { + final double d = values[i] - m; + accum3 += d * d * d; + } + accum3 /= variance * AccurateMath.sqrt(variance); - double accum3 = 0.0; - for (int i = begin; i < begin + length; i++) { - final double d = values[i] - m; - accum3 += d * d * d; + // Get N + double n0 = length; + + // Calculate skewness + skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3; } - accum3 /= variance * AccurateMath.sqrt(variance); - - // Get N - double n0 = length; - - // Calculate skewness - skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3; } return skew; } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java index e59577c8f..aa0124f2a 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java @@ -60,4 +60,9 @@ public class SkewnessTest extends StorelessUnivariateStatisticAbstractTest{ Assert.assertFalse(Double.isNaN(skew.getResult())); } + @Test + public void testZeroSkewness() { + final double[] values = {2, 2, 2, 2}; + Assert.assertEquals(0, new Skewness().evaluate(values), 0.0); + } }