/*
* Copyright 2015, 2016 Tagir Valeev
*
* 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 one.util.streamex;
import static one.util.streamex.StreamExInternals.*;
import static one.util.streamex.TestHelpers.*;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import one.util.streamex.LongStreamEx;
import one.util.streamex.MoreCollectors;
import org.junit.Test;
/**
* @author Tagir Valeev
*/
public class AverageLongTest {
@Test
public void testAverageLongNoOverflow() {
AverageLong avg = new AverageLong();
assertFalse(avg.result().isPresent());
avg.accept(1);
avg.accept(2);
avg.accept(3);
assertEquals(2.0, avg.result().getAsDouble(), 0.0);
avg.accept(2);
avg.accept(-4);
avg.accept(8);
assertEquals(2.0, avg.result().getAsDouble(), 0.0);
AverageLong avg1 = new AverageLong();
avg1.accept(-2);
AverageLong avg2 = new AverageLong();
avg2.accept(-2);
assertEquals(-2.0, avg1.combine(avg2).result().getAsDouble(), 0.0);
withRandom(r -> {
int[] input = r.ints(1000).toArray();
OptionalDouble expected = IntStream.of(input).average();
assertEquals(expected, Arrays.stream(input)
.collect(AverageLong::new, AverageLong::accept, AverageLong::combine).result());
assertEquals(expected, Arrays.stream(input).parallel().collect(AverageLong::new, AverageLong::accept,
AverageLong::combine).result());
});
}
@Test
public void testCombine() {
withRandom(r -> repeat(100, i -> {
AverageLong avg1 = new AverageLong();
AverageLong avg2 = new AverageLong();
long[] set1 = r.longs(100).toArray();
long[] set2 = r.longs(100).toArray();
double expected = LongStreamEx.of(set1).append(set2).boxed().collect(getBigIntegerAverager()).getAsDouble();
LongStream.of(set1).forEach(avg1::accept);
LongStream.of(set2).forEach(avg2::accept);
assertEquals(expected, avg1.combine(avg2).result().getAsDouble(), Math.abs(expected / 1e14));
}));
}
@Test
public void testCompareToBigInteger() {
withRandom(r -> {
long[] input = LongStreamEx.of(r, 1000).toArray();
Supplier<LongStream> supplier = () -> Arrays.stream(input);
double expected = supplier.get().boxed().collect(getBigIntegerAverager()).getAsDouble();
assertEquals(expected, supplier.get().collect(AverageLong::new, AverageLong::accept, AverageLong::combine)
.result().getAsDouble(), Math.abs(expected) / 1e14);
assertEquals(expected, supplier.get().parallel().collect(AverageLong::new, AverageLong::accept,
AverageLong::combine).result().getAsDouble(), Math.abs(expected) / 1e14);
});
}
private Collector<Long, ?, OptionalDouble> getBigIntegerAverager() {
BiFunction<BigInteger, Long, OptionalDouble> finisher = (BigInteger sum, Long cnt) -> cnt == 0L ? OptionalDouble
.empty()
: OptionalDouble.of(new BigDecimal(sum).divide(BigDecimal.valueOf(cnt), MathContext.DECIMAL64)
.doubleValue());
return MoreCollectors.pairing(Collectors.reducing(BigInteger.ZERO,
BigInteger::valueOf, BigInteger::add), Collectors.counting(), finisher);
}
}