1a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin/* 2a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * 5a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * This code is free software; you can redistribute it and/or modify it 6a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * under the terms of the GNU General Public License version 2 only, as 7a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * published by the Free Software Foundation. 8a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * 9a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * This code is distributed in the hope that it will be useful, but WITHOUT 10a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * version 2 for more details (a copy is included in the LICENSE file that 13a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * accompanied this code). 14a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * 15a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * You should have received a copy of the GNU General Public License version 16a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * 2 along with this work; if not, write to the Free Software Foundation, 17a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * 19a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * or visit www.oracle.com if you need additional information or have any 21a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * questions. 22a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 23a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 24a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkinimport java.util.*; 25a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkinimport java.util.function.*; 26a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkinimport java.util.stream.*; 27a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 28a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkinimport static java.lang.Double.*; 29a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 30a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin/* 31a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * @test 32a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * @bug 8006572 8030212 33a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * @summary Test for use of non-naive summation in stream-related sum and average operations. 34a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 35a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkinpublic class TestDoubleSumAverage { 36a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin public static void main(String... args) { 37a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin int failures = 0; 38a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 39a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += testZeroAverageOfNonEmptyStream(); 40a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += testForCompenstation(); 41a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += testNonfiniteSum(); 42a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 43a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin if (failures > 0) { 44a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin throw new RuntimeException("Found " + failures + " numerical failure(s)."); 45a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 46a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 47a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 48a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin /** 49a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Test to verify that a non-empty stream with a zero average is non-empty. 50a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 51a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin private static int testZeroAverageOfNonEmptyStream() { 52a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin Supplier<DoubleStream> ds = () -> DoubleStream.iterate(0.0, e -> 0.0).limit(10); 53a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 54a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return compareUlpDifference(0.0, ds.get().average().getAsDouble(), 0); 55a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 56a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 57a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin /** 58a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Compute the sum and average of a sequence of double values in 59a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * various ways and report an error if naive summation is used. 60a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 61a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin private static int testForCompenstation() { 62a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin int failures = 0; 63a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 64a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin /* 65a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * The exact sum of the test stream is 1 + 1e6*ulp(1.0) but a 66a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * naive summation algorithm will return 1.0 since (1.0 + 67a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * ulp(1.0)/2) will round to 1.0 again. 68a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 69a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double base = 1.0; 70a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double increment = Math.ulp(base)/2.0; 71a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin int count = 1_000_001; 72a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 73a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double expectedSum = base + (increment * (count - 1)); 74a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double expectedAvg = expectedSum / count; 75a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 76a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin // Factory for double a stream of [base, increment, ..., increment] limited to a size of count 77a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin Supplier<DoubleStream> ds = () -> DoubleStream.iterate(base, e -> increment).limit(count); 78a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 79a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics stats = ds.get().collect(DoubleSummaryStatistics::new, 80a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics::accept, 81a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics::combine); 82a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 83a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedSum, stats.getSum(), 3); 84a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedAvg, stats.getAverage(), 3); 85a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 86a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedSum, 87a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin ds.get().sum(), 3); 88a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedAvg, 89a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin ds.get().average().getAsDouble(), 3); 90a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 91a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedSum, 92a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin ds.get().boxed().collect(Collectors.summingDouble(d -> d)), 3); 93a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expectedAvg, 94a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin ds.get().boxed().collect(Collectors.averagingDouble(d -> d)),3); 95a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return failures; 96a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 97a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 98a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin private static int testNonfiniteSum() { 99a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin int failures = 0; 100a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 101a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin Map<Supplier<DoubleStream>, Double> testCases = new LinkedHashMap<>(); 102a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(MAX_VALUE, MAX_VALUE), POSITIVE_INFINITY); 103a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(-MAX_VALUE, -MAX_VALUE), NEGATIVE_INFINITY); 104a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 105a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(1.0d, POSITIVE_INFINITY, 1.0d), POSITIVE_INFINITY); 106a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(POSITIVE_INFINITY), POSITIVE_INFINITY); 107a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(POSITIVE_INFINITY, POSITIVE_INFINITY), POSITIVE_INFINITY); 108a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(POSITIVE_INFINITY, POSITIVE_INFINITY, 0.0), POSITIVE_INFINITY); 109a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 110a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(1.0d, NEGATIVE_INFINITY, 1.0d), NEGATIVE_INFINITY); 111a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NEGATIVE_INFINITY), NEGATIVE_INFINITY); 112a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NEGATIVE_INFINITY, NEGATIVE_INFINITY), NEGATIVE_INFINITY); 113a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NEGATIVE_INFINITY, NEGATIVE_INFINITY, 0.0), NEGATIVE_INFINITY); 114a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 115a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(1.0d, NaN, 1.0d), NaN); 116a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NaN), NaN); 117a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(1.0d, NEGATIVE_INFINITY, POSITIVE_INFINITY, 1.0d), NaN); 118a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(1.0d, POSITIVE_INFINITY, NEGATIVE_INFINITY, 1.0d), NaN); 119a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(POSITIVE_INFINITY, NaN), NaN); 120a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NEGATIVE_INFINITY, NaN), NaN); 121a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NaN, POSITIVE_INFINITY), NaN); 122a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin testCases.put(() -> DoubleStream.of(NaN, NEGATIVE_INFINITY), NaN); 123a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 124a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin for(Map.Entry<Supplier<DoubleStream>, Double> testCase : testCases.entrySet()) { 125a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin Supplier<DoubleStream> ds = testCase.getKey(); 126a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double expected = testCase.getValue(); 127a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 128a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics stats = ds.get().collect(DoubleSummaryStatistics::new, 129a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics::accept, 130a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin DoubleSummaryStatistics::combine); 131a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 132a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, stats.getSum(), 0); 133a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, stats.getAverage(), 0); 134a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 135a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, ds.get().sum(), 0); 136a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, ds.get().average().getAsDouble(), 0); 137a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 138a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, ds.get().boxed().collect(Collectors.summingDouble(d -> d)), 0); 139a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin failures += compareUlpDifference(expected, ds.get().boxed().collect(Collectors.averagingDouble(d -> d)), 0); 140a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 141a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 142a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return failures; 143a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 144a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 145a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin /** 146a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin * Compute the ulp difference of two double values and compare against an error threshold. 147a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin */ 148a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin private static int compareUlpDifference(double expected, double computed, double threshold) { 149a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin if (!Double.isFinite(expected)) { 150a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin // Handle NaN and infinity cases 151a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin if (Double.compare(expected, computed) == 0) 152a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return 0; 153a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin else { 154a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin System.err.printf("Unexpected sum, %g rather than %g.%n", 155a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin computed, expected); 156a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return 1; 157a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 158a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 159a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 160a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin double ulpDifference = Math.abs(expected - computed) / Math.ulp(expected); 161a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin 162a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin if (ulpDifference > threshold) { 163a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin System.err.printf("Numerical summation error too large, %g ulps rather than %g.%n", 164a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin ulpDifference, threshold); 165a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return 1; 166a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } else 167a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin return 0; 168a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin } 169a405b7ea164e472bcf6b75d9890021bd82e4d60dIgor Murashkin} 170