private void testCorrectnessOfErrorFunction(List<Number> inputList) throws Exception {
    int inRange = 0;
    int numberOfRuns = 1000;
    double sampleRatio = 1 / (double) WEIGHT;
    double actual = getExpectedValue(inputList);
    Random rand = new Random(1);

    for (int i = 0; i < numberOfRuns; i++) {
      // Compute Sampled Value using sampledList (numberOfRuns times)
      ImmutableList.Builder<Number> sampledList = ImmutableList.builder();
      for (Number x : inputList) {
        if (rand.nextDouble() < sampleRatio) {
          sampledList.add(x);
        }
      }

      BlockBuilder builder = getType().createBlockBuilder(new BlockBuilderStatus());
      for (Number sample : sampledList.build()) {
        if (getType() == BIGINT) {
          BIGINT.writeLong(builder, sample.longValue());
        } else if (getType() == DOUBLE) {
          DOUBLE.writeDouble(builder, sample.doubleValue());
        } else {
          throw new AssertionError("Can only handle longs and doubles");
        }
      }
      Page page = new Page(builder.build());
      page = OperatorAssertion.appendSampleWeight(ImmutableList.of(page), WEIGHT).get(0);
      Accumulator accumulator =
          getFunction()
              .bind(
                  ImmutableList.of(0),
                  Optional.<Integer>absent(),
                  Optional.of(page.getChannelCount() - 1),
                  getConfidence())
              .createAccumulator();

      accumulator.addInput(page);
      Block result = accumulator.evaluateFinal();

      String approxValue =
          BlockAssertions.toValues(accumulator.getFinalType(), result).get(0).toString();
      double approx = Double.parseDouble(approxValue.split(" ")[0]);
      double error = Double.parseDouble(approxValue.split(" ")[2]);

      // Check if actual answer lies within [approxAnswer - error, approxAnswer + error]
      if (Math.abs(approx - actual) <= error) {
        inRange++;
      }
    }

    BinomialDistribution binomial = new BinomialDistribution(numberOfRuns, getConfidence());
    int lowerBound = binomial.inverseCumulativeProbability(0.01);
    int upperBound = binomial.inverseCumulativeProbability(0.99);
    assertTrue(
        lowerBound < inRange && inRange < upperBound,
        String.format(
            "%d out of %d passed. Expected [%d, %d]",
            inRange, numberOfRuns, lowerBound, upperBound));
  }
  @Setup
  public void setup() {
    Random random = new Random();
    RowExpression[] arguments = new RowExpression[1 + inListCount];
    switch (type) {
      case StandardTypes.BIGINT:
        prestoType = BIGINT;
        for (int i = 1; i <= inListCount; i++) {
          arguments[i] = constant((long) random.nextInt(), BIGINT);
        }
        break;
      case StandardTypes.DOUBLE:
        prestoType = DOUBLE;
        for (int i = 1; i <= inListCount; i++) {
          arguments[i] = constant(random.nextDouble(), DOUBLE);
        }
        break;
      case StandardTypes.VARCHAR:
        prestoType = VARCHAR;
        for (int i = 1; i <= inListCount; i++) {
          arguments[i] = constant(Slices.utf8Slice(Long.toString(random.nextLong())), VARCHAR);
        }
        break;
      default:
        throw new IllegalStateException();
    }

    arguments[0] = field(0, prestoType);
    RowExpression project = field(0, prestoType);

    PageBuilder pageBuilder = new PageBuilder(ImmutableList.of(prestoType));
    for (int i = 0; i < 10_000; i++) {
      pageBuilder.declarePosition();

      switch (type) {
        case StandardTypes.BIGINT:
          BIGINT.writeLong(pageBuilder.getBlockBuilder(0), random.nextInt());
          break;
        case StandardTypes.DOUBLE:
          DOUBLE.writeDouble(pageBuilder.getBlockBuilder(0), random.nextDouble());
          break;
        case StandardTypes.VARCHAR:
          VARCHAR.writeSlice(
              pageBuilder.getBlockBuilder(0), Slices.utf8Slice(Long.toString(random.nextLong())));
          break;
      }
    }
    inputPage = pageBuilder.build();

    RowExpression filter =
        call(
            new Signature(IN, SCALAR, parseTypeSignature(StandardTypes.BOOLEAN)),
            BOOLEAN,
            arguments);

    processor =
        new ExpressionCompiler(MetadataManager.createTestMetadataManager())
            .compilePageProcessor(filter, ImmutableList.of(project))
            .get();
  }
 private static Block createFixWidthValueBlock(int positionCount, int mapSize) {
   BlockBuilder valueBlockBuilder =
       DOUBLE.createBlockBuilder(new BlockBuilderStatus(), positionCount * mapSize);
   for (int i = 0; i < positionCount * mapSize; i++) {
     DOUBLE.writeDouble(valueBlockBuilder, ThreadLocalRandom.current().nextDouble());
   }
   return valueBlockBuilder.build();
 }
 @Override
 public Block getSequenceBlock(int start, int length) {
   BlockBuilder blockBuilder = getType().createBlockBuilder(new BlockBuilderStatus());
   for (int i = start; i < start + length; i++) {
     if (getType() == BIGINT) {
       BIGINT.writeLong(blockBuilder, (long) i);
     } else {
       DOUBLE.writeDouble(blockBuilder, (double) i);
     }
   }
   return blockBuilder.build();
 }
  @OutputFunction("array<double>")
  public static void output(DigestAndPercentileArrayState state, BlockBuilder out) {
    QuantileDigest digest = state.getDigest();
    List<Double> percentiles = state.getPercentiles();

    if (percentiles == null || digest == null) {
      out.appendNull();
      return;
    }

    BlockBuilder blockBuilder = out.beginBlockEntry();

    for (int i = 0; i < percentiles.size(); i++) {
      Double percentile = percentiles.get(i);
      DOUBLE.writeDouble(blockBuilder, sortableLongToDouble(digest.getQuantile(percentile)));
    }

    out.closeEntry();
  }
 @Override
 public void addFloat(float value) {
   DOUBLE.writeDouble(builder, value);
   wroteValue = true;
 }
 @Override
 public void addDouble(double value) {
   DOUBLE.writeDouble(builder, value);
   wroteValue = true;
 }