src/share/classes/java/util/stream/Collectors.java

Print this page

        

@@ -505,20 +505,24 @@
      */
     public static <T> Collector<T, ?, Double>
     summingDouble(ToDoubleFunction<? super T> mapper) {
         /*
          * In the arrays allocated for the collect operation, index 0
-         * holds the high-order bits of the running sum and index 1
-         * holds the low-order bits of the sum computed via
-         * compensated summation.
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
          */
         return new CollectorImpl<>(
-                () -> new double[2],
-                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); },
-                (a, b) -> { sumWithCompensation(a, b[0]); return sumWithCompensation(a, b[1]); },
-                // Better error bounds to add both terms as the final sum
-                a -> a[0] + a[1],
+                () -> new double[3],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
+                            a[2] += mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]);
+                            a[2] += b[2];
+                            return sumWithCompensation(a, b[1]); },
+                a -> computeFinalSum(a),
                 CH_NOID);
     }
 
     /**
      * Incorporate a new double value using Kahan summation /

@@ -538,10 +542,24 @@
         intermediateSum[1] = (velvel - sum) - tmp;
         intermediateSum[0] = velvel;
         return intermediateSum;
     }
 
+    /**
+     * If the compensated sum is spuriously NaN from accumulating one
+     * or more same-signed infinite values, return the
+     * correctly-signed infinity stored in the simple sum.
+     */
+    static double computeFinalSum(double[] summands) {
+        // Better error bounds to add both terms as the final sum
+        double tmp = summands[0] + summands[1];
+        double simpleSum = summands[summands.length - 1];
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            return simpleSum;
+        else
+            return tmp;
+    }
 
     /**
      * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued
      * function applied to the input elements.  If no elements are present,
      * the result is 0.

@@ -606,15 +624,14 @@
          * holds the high-order bits of the running sum, index 1 holds
          * the low-order bits of the sum computed via compensated
          * summation, and index 2 holds the number of values seen.
          */
         return new CollectorImpl<>(
-                () -> new double[3],
-                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; },
-                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; return a; },
-                // Better error bounds to add both terms as the final sum to compute average
-                a -> (a[2] == 0) ? 0.0d : ((a[0] + a[1]) / a[2]),
+                () -> new double[4],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
+                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
                 CH_NOID);
     }
 
     /**
      * Returns a {@code Collector} which performs a reduction of its