### Question:
DecimalAverageAggregation extends SqlAggregationFunction { @VisibleForTesting public static BigDecimal average(LongDecimalWithOverflowAndLongState state, DecimalType type) { BigDecimal sum = new BigDecimal(Decimals.decodeUnscaledValue(state.getLongDecimal()), type.getScale()); BigDecimal count = BigDecimal.valueOf(state.getLong()); if (state.getOverflow() != 0) { BigInteger overflowMultiplier = TWO.shiftLeft(UNSCALED_DECIMAL_128_SLICE_LENGTH * 8 - 2); BigInteger overflow = overflowMultiplier.multiply(BigInteger.valueOf(state.getOverflow())); sum = sum.add(new BigDecimal(overflow)); } return sum.divide(count, type.getScale(), ROUND_HALF_UP); } DecimalAverageAggregation(); @Override List<TypeSignature> getIntermediateTypes(FunctionBinding functionBinding); @Override InternalAggregationFunction specialize(FunctionBinding functionBinding); static void inputShortDecimal(Type type, LongDecimalWithOverflowAndLongState state, Block block, int position); static void inputLongDecimal(Type type, LongDecimalWithOverflowAndLongState state, Block block, int position); static void combine(LongDecimalWithOverflowAndLongState state, LongDecimalWithOverflowAndLongState otherState); static void outputShortDecimal(DecimalType type, LongDecimalWithOverflowAndLongState state, BlockBuilder out); static void outputLongDecimal(DecimalType type, LongDecimalWithOverflowAndLongState state, BlockBuilder out); @VisibleForTesting static BigDecimal average(LongDecimalWithOverflowAndLongState state, DecimalType type); static final DecimalAverageAggregation DECIMAL_AVERAGE_AGGREGATION; }### Answer:
@Test public void testOverflow() { addToState(state, TWO.pow(126)); assertEquals(state.getLong(), 1); assertEquals(state.getOverflow(), 0); assertEquals(state.getLongDecimal(), unscaledDecimal(TWO.pow(126))); addToState(state, TWO.pow(126)); assertEquals(state.getLong(), 2); assertEquals(state.getOverflow(), 1); assertEquals(state.getLongDecimal(), unscaledDecimal(0)); assertEquals(average(state, TYPE), new BigDecimal(TWO.pow(126))); }
@Test public void testUnderflow() { addToState(state, TWO.pow(126).negate()); assertEquals(state.getLong(), 1); assertEquals(state.getOverflow(), 0); assertEquals(state.getLongDecimal(), unscaledDecimal(TWO.pow(126).negate())); addToState(state, TWO.pow(126).negate()); assertEquals(state.getLong(), 2); assertEquals(state.getOverflow(), -1); assertEquals(UnscaledDecimal128Arithmetic.compare(state.getLongDecimal(), unscaledDecimal(0)), 0); assertEquals(average(state, TYPE), new BigDecimal(TWO.pow(126).negate())); }
@Test public void testUnderflowAfterOverflow() { addToState(state, TWO.pow(126)); addToState(state, TWO.pow(126)); addToState(state, TWO.pow(125)); assertEquals(state.getOverflow(), 1); assertEquals(state.getLongDecimal(), unscaledDecimal(TWO.pow(125))); addToState(state, TWO.pow(126).negate()); addToState(state, TWO.pow(126).negate()); addToState(state, TWO.pow(126).negate()); assertEquals(state.getOverflow(), 0); assertEquals(state.getLongDecimal(), unscaledDecimal(TWO.pow(125).negate())); assertEquals(average(state, TYPE), new BigDecimal(TWO.pow(125).negate().divide(BigInteger.valueOf(6)))); }