You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2023/12/30 08:32:09 UTC

(commons-statistics) 05/06: STATISTICS-83: Benchmark handling of non-finite values in mean/sum

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-statistics.git

commit 7d553b2b7eaf8ee6300a11bfbb689e4f346348d7
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Fri Dec 29 23:39:49 2023 +0000

    STATISTICS-83: Benchmark handling of non-finite values in mean/sum
---
 .../jmh/descriptive/MomentPerformance.java         | 133 ++++++++++++++++++++-
 1 file changed, 132 insertions(+), 1 deletion(-)

diff --git a/commons-statistics-examples/examples-jmh/src/main/java/org/apache/commons/statistics/examples/jmh/descriptive/MomentPerformance.java b/commons-statistics-examples/examples-jmh/src/main/java/org/apache/commons/statistics/examples/jmh/descriptive/MomentPerformance.java
index a071083..ae4ba27 100644
--- a/commons-statistics-examples/examples-jmh/src/main/java/org/apache/commons/statistics/examples/jmh/descriptive/MomentPerformance.java
+++ b/commons-statistics-examples/examples-jmh/src/main/java/org/apache/commons/statistics/examples/jmh/descriptive/MomentPerformance.java
@@ -56,12 +56,20 @@ public class MomentPerformance {
     private static final String SUM_MEAN = "SumMean";
     /** Extended precision summation mean implementation. */
     private static final String EXTENDED_SUM_MEAN = "ExtendedSumMean";
+    /** Extended precision summation (using Numbers Sum). */
+    private static final String NUMBERS_SUM = "NumbersSum";
+    /** Extended precision summation (using Numbers Sum) with computation of non-finite value. */
+    private static final String NUMBERS_SUM2 = "NumbersSum2";
     /** Rolling mean implementation. */
     private static final String ROLLING_MEAN = "RollingMean";
     /** Safe rolling mean implementation. */
     private static final String SAFE_ROLLING_MEAN = "SafeRollingMean";
     /** Safe rolling mean implementation. */
     private static final String SCALED_ROLLING_MEAN = "ScaledRollingMean";
+    /** Safe rolling mean implementation with computation of non-finite value. */
+    private static final String SCALED_ROLLING_MEAN2 = "ScaledRollingMean2";
+    /** Safe rolling mean implementation with computation of non-finite value. */
+    private static final String SCALED_ROLLING_MEAN3 = "ScaledRollingMean3";
     /** Inline rolling mean implementation for array-based creation. */
     private static final String INLINE_ROLLING_MEAN = "InlineRollingMean";
     /** Inline safe rolling mean implementation for array-based creation. */
@@ -104,7 +112,8 @@ public class MomentPerformance {
     @State(Scope.Benchmark)
     public static class ActionSource {
         /** Name of the source. */
-        @Param({MEAN, ROLLING_MEAN, SAFE_ROLLING_MEAN, SCALED_ROLLING_MEAN, SUM_MEAN, EXTENDED_SUM_MEAN})
+        @Param({MEAN, ROLLING_MEAN, SAFE_ROLLING_MEAN, SCALED_ROLLING_MEAN, SUM_MEAN, EXTENDED_SUM_MEAN,
+            SCALED_ROLLING_MEAN2, SCALED_ROLLING_MEAN3, NUMBERS_SUM, NUMBERS_SUM2})
         private String name;
 
         /** The action. */
@@ -130,10 +139,18 @@ public class MomentPerformance {
                 action = SafeRollingFirstMoment::new;
             } else if (SCALED_ROLLING_MEAN.equals(name)) {
                 action = ScaledRollingFirstMoment::new;
+            } else if (SCALED_ROLLING_MEAN2.equals(name)) {
+                action = ScaledRollingFirstMoment2::new;
+            } else if (SCALED_ROLLING_MEAN3.equals(name)) {
+                action = ScaledRollingFirstMoment3::new;
             } else if (SUM_MEAN.equals(name)) {
                 action = SumFirstMoment::new;
             } else if (EXTENDED_SUM_MEAN.equals(name)) {
                 action = ExtendedSumFirstMoment::new;
+            } else if (NUMBERS_SUM.equals(name)) {
+                action = NumbersSum::new;
+            } else if (NUMBERS_SUM2.equals(name)) {
+                action = NumbersSum2::new;
             } else {
                 throw new IllegalStateException("Unknown action: " + name);
             }
@@ -275,6 +292,72 @@ public class MomentPerformance {
         }
     }
 
+    /**
+     * A rolling first raw moment of {@code double} data safe to overflow of any finite
+     * values (e.g. [MAX_VALUE, -MAX_VALUE]). This includes computation of the correct
+     * non-finite value.
+     */
+    static class ScaledRollingFirstMoment2 implements DoubleConsumer, DoubleSupplier {
+        /** Count of values that have been added. */
+        private long n;
+
+        /** First moment of values that have been added. */
+        private double m1;
+
+        /** Non-finite result. This is the sum of non-finite values. */
+        private double nonFiniteValue;
+
+        @Override
+        public void accept(double value) {
+            if (!Double.isFinite(value)) {
+                nonFiniteValue += value;
+            }
+            m1 += (value * 0.5 - m1) / ++n;
+        }
+
+        @Override
+        public double getAsDouble() {
+            final double m = m1 * 2;
+            if (Double.isFinite(m)) {
+                return n == 0 ? Double.NaN : m;
+            }
+            // Non-finite value encountered
+            return nonFiniteValue;
+        }
+    }
+
+    /**
+     * A rolling first raw moment of {@code double} data safe to overflow of any finite
+     * values (e.g. [MAX_VALUE, -MAX_VALUE]). This includes computation of the correct
+     * non-finite value.
+     */
+    static class ScaledRollingFirstMoment3 implements DoubleConsumer, DoubleSupplier {
+        /** Count of values that have been added. */
+        private long n;
+
+        /** First moment of values that have been added. */
+        private double m1;
+
+        /** Non-finite result. This is the sum of non-finite values. */
+        private double nonFiniteValue;
+
+        @Override
+        public void accept(double value) {
+            nonFiniteValue += value * Double.MIN_NORMAL;
+            m1 += (value * 0.5 - m1) / ++n;
+        }
+
+        @Override
+        public double getAsDouble() {
+            final double m = m1 * 2;
+            if (Double.isFinite(m)) {
+                return n == 0 ? Double.NaN : m;
+            }
+            // Non-finite value encountered
+            return nonFiniteValue;
+        }
+    }
+
     /**
      * A mean using a sum.
      */
@@ -331,6 +414,54 @@ public class MomentPerformance {
         }
     }
 
+    /**
+     * A sum using an Commons Numbers {@link Sum}.
+     */
+    static class NumbersSum implements DoubleConsumer, DoubleSupplier {
+        /** Sum of values that have been added. */
+        private Sum sum = Sum.create();
+
+        @Override
+        public void accept(double value) {
+            sum.add(value);
+        }
+
+        @Override
+        public double getAsDouble() {
+            return sum.getAsDouble();
+        }
+    }
+
+    /**
+     * A sum using an Commons Numbers {@link Sum} with computation of the correct
+     * non-finite value.
+     */
+    static class NumbersSum2 implements DoubleConsumer, DoubleSupplier {
+        /** Sum of values that have been added. */
+        private Sum sum = Sum.create();
+
+        /** Non-finite result. This is the sum of non-finite values. */
+        private double nonFiniteValue;
+
+        @Override
+        public void accept(double value) {
+            if (!Double.isFinite(value)) {
+                nonFiniteValue += value;
+            }
+            sum.add(value);
+        }
+
+        @Override
+        public double getAsDouble() {
+            final double s = sum.getAsDouble();
+            if (Double.isFinite(s)) {
+                return s;
+            }
+            // Non-finite value encountered
+            return nonFiniteValue;
+        }
+    }
+
     /**
      * Apply the action to each value.
      *