blob: 191f3acfb32d17766c87e5b8a7eaa28dcbfccfbd [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.emultest.java8.util;
import com.google.gwt.emultest.java.util.EmulTestBase;
import static java.lang.Double.MAX_VALUE;
import static java.lang.Double.MIN_VALUE;
import static java.lang.Double.NEGATIVE_INFINITY;
import static java.lang.Double.NaN;
import static java.lang.Double.POSITIVE_INFINITY;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
/**
* Tests {@link DoubleSummaryStatistics}.
*/
public class DoubleSummaryStatisticsTest extends EmulTestBase {
private DoubleSummaryStatistics stats;
@Override
protected void gwtSetUp() throws Exception {
stats = new DoubleSummaryStatistics();
}
public void testAverageAndSumWithCompensation() throws Exception {
assertEquals(0d, stats.getAverage());
assertEquals(0d, stats.getSum());
double initial = 1.0d;
long count = 100000;
// 'precision' is the hardcoded result of Math.ulp(initial) in JVM,
// since GWT does not emulate Math.ulp().
// This value represents the distance from 'initial' (1.0d) to the
// previous/next double. If we add half or less of that distance/precision
// to 'initial' then the result will be truncated to 'initial' again due to
// floating point arithmetic rounding.
// With Kahan summation such rounding errors are detected and compensated
// so the summation result should (nearly) equal the expected sum.
double precision = 2.220446049250313E-16;
double value = precision / 2;
double expectedSum = initial + (count * value);
long expectedCount = count + 1;
double expectedAverage = expectedSum / expectedCount;
stats.accept(initial);
for (int i = 0; i < count; ++i) {
stats.accept(value);
}
// TODO (jnehlmeier): While delta = 0 works we probably want to allow some error?
// Or maybe use ulp differences instead of a delta?
assertEquals(expectedAverage, stats.getAverage(), 0);
assertEquals(expectedSum, stats.getSum(), 0);
}
public void testCombine() throws Exception {
stats.accept(1.0d);
stats.accept(2.0d);
DoubleSummaryStatistics otherStats = new DoubleSummaryStatistics();
otherStats.accept(3.0d);
otherStats.accept(4.0d);
stats.combine(otherStats);
assertEquals(2.5d, stats.getAverage());
assertEquals(1d, stats.getMin());
assertEquals(4d, stats.getMax());
assertEquals(10d, stats.getSum());
assertEquals(4, stats.getCount());
}
public void testCountMaxMin() {
assertEquals(0, stats.getCount());
assertEquals(NEGATIVE_INFINITY, stats.getMax());
assertEquals(POSITIVE_INFINITY, stats.getMin());
double[][] testData = {
// aDouble, max, min
{ 1.0, 1.0, 1.0 },
{ -1.0, 1.0, -1.0 },
{ 2.5, 2.5, -1.0 },
{ -2.5, 2.5, -2.5 },
{ MAX_VALUE, MAX_VALUE, -2.5 },
{ MIN_VALUE, MAX_VALUE, -2.5 },
{ POSITIVE_INFINITY, POSITIVE_INFINITY, -2.5 },
{ NEGATIVE_INFINITY, POSITIVE_INFINITY, NEGATIVE_INFINITY },
};
for (int i = 0; i < testData.length; ++i) {
long expectedCount = i + 1;
double aDouble = testData[i][0];
double expectedMax = testData[i][1];
double expectedMin = testData[i][2];
stats.accept(aDouble);
assertEquals(expectedCount, stats.getCount());
assertEquals(expectedMax, stats.getMax());
assertEquals(expectedMin, stats.getMin());
}
}
public void testInfinity() {
stats.accept(NEGATIVE_INFINITY);
stats.accept(NEGATIVE_INFINITY);
assertEquals(NEGATIVE_INFINITY, stats.getAverage());
assertEquals(NEGATIVE_INFINITY, stats.getMax());
assertEquals(NEGATIVE_INFINITY, stats.getMin());
assertEquals(NEGATIVE_INFINITY, stats.getSum());
stats.accept(POSITIVE_INFINITY);
assertTrue(Double.isNaN(stats.getAverage()));
assertEquals(POSITIVE_INFINITY, stats.getMax());
assertEquals(NEGATIVE_INFINITY, stats.getMin());
assertTrue(Double.isNaN(stats.getSum()));
stats = new DoubleSummaryStatistics();
stats.accept(POSITIVE_INFINITY);
stats.accept(POSITIVE_INFINITY);
assertEquals(POSITIVE_INFINITY, stats.getAverage());
assertEquals(POSITIVE_INFINITY, stats.getMax());
assertEquals(POSITIVE_INFINITY, stats.getMin());
assertEquals(POSITIVE_INFINITY, stats.getSum());
stats.accept(NEGATIVE_INFINITY);
assertTrue(Double.isNaN(stats.getAverage()));
assertEquals(POSITIVE_INFINITY, stats.getMax());
assertEquals(NEGATIVE_INFINITY, stats.getMin());
assertTrue(Double.isNaN(stats.getSum()));
}
public void testNaN() {
List<Double> testData = Arrays.asList(
NaN, -1.5d, 2.5d, MAX_VALUE, MIN_VALUE, NaN,
NEGATIVE_INFINITY, POSITIVE_INFINITY);
stats.accept(5.0d);
for (Double aDouble : testData) {
stats.accept(aDouble);
assertTrue(Double.isNaN(stats.getAverage()));
assertTrue(Double.isNaN(stats.getMax()));
assertTrue(Double.isNaN(stats.getMin()));
assertTrue(Double.isNaN(stats.getSum()));
}
}
}