code: private static <T> void linearTimeIncrementHistogramCounters(final T[] samples, final int offset,
        final int numSamples, final long weight, final T[] splitPoints, final double[] counters,
        final Comparator<? super T> comparator) {
      int i = 0;
      int j = 0;
      while ((i < numSamples) && (j < splitPoints.length)) {
        if (comparator.compare(samples[i + offset], splitPoints[j]) < 0) {
          counters[j] += weight; // this sample goes into this bucket
          i++; // move on to next sample and see whether it also goes into this bucket
        } else {
          j++; // no more samples for this bucket. move on the next bucket.
        }
      }
  
      // now either i == numSamples(we are out of samples), or
      // j == numSplitPoints(out of buckets, but there are more samples remaining)
      // we only need to do something in the latter case.
      if (j == splitPoints.length) {
        counters[j] += (weight * (numSamples - i));
      }
    }
docs: This one does a linear time simultaneous walk of the samples and splitPoints. Because this
  internal procedure is called multiple times, we require the caller to ensure these 3 properties:
  <ol>
  <li>samples array must be sorted.</li>
  <li>splitPoints must be unique and sorted</li>
  <li>number of SplitPoints + 1 == counters.length</li>
  </ol>
  @param <T> the data type
  @param samples sorted array of samples
  @param offset into samples array
  @param numSamples number of samples in samples array
  @param weight of the samples
  @param splitPoints must be unique and sorted. Number of splitPoints + 1 = counters.length.
  @param counters array of counters
  @param comparator the comparator for data type T