diff --git a/src/internal_modules/roc_stat/mov_histogram.h b/src/internal_modules/roc_stat/mov_histogram.h index 46fdb0d0f..6b8357324 100644 --- a/src/internal_modules/roc_stat/mov_histogram.h +++ b/src/internal_modules/roc_stat/mov_histogram.h @@ -86,6 +86,26 @@ template class MovHistogram { return bins_[bin_index]; } + //! Get approximated moving quantile. + //! @note + //! Has O(num_bins) complexity. + T mov_quantile(const double quantile) const { + T cap; + size_t count = 0; + + for (size_t bin_index = 0; bin_index < num_bins_; bin_index++) { + cap = value_range_min_ + bin_width_ * (bin_index + 1); + count += bins_[bin_index]; + + const double ratio = (double)count / ring_buffer_.size(); + if (ratio >= quantile) { + break; + } + } + + return cap; + } + //! Add a value to the histogram. //! @note //! Has O(1) complexity. diff --git a/src/tests/roc_stat/test_mov_histogram.cpp b/src/tests/roc_stat/test_mov_histogram.cpp index a533b4912..6f1d321b9 100644 --- a/src/tests/roc_stat/test_mov_histogram.cpp +++ b/src/tests/roc_stat/test_mov_histogram.cpp @@ -213,5 +213,50 @@ TEST(mov_histogram, clamping_values) { LONGS_EQUAL(3, hist.mov_counter(9)); } +TEST(mov_histogram, quantile) { + const size_t value_range_min = 0; + const size_t value_range_max = 100; + const size_t num_bins = 10; + const size_t win_length = 10; + + MovHistogram hist(arena, value_range_min, value_range_max, num_bins, + win_length); + CHECK(hist.is_valid()); + + hist.add(5); + hist.add(15); + hist.add(25); + hist.add(35); + hist.add(45); + hist.add(55); + hist.add(65); + hist.add(75); + hist.add(85); + hist.add(95); + + // 0 1 2 3 4 5 6 7 8 9 + // +---+---+---+---+---+---+---+---+---+---+ + // | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | + // +---+---+---+---+---+---+---+---+---+---+ + + LONGS_EQUAL(100, hist.mov_quantile(1.0)); + LONGS_EQUAL(40, hist.mov_quantile(0.4)); + LONGS_EQUAL(10, hist.mov_quantile(0.1)); + + hist.add(75); + hist.add(75); + hist.add(85); + + // 0 1 2 3 4 5 6 7 8 9 + // +---+---+---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 3 | 2 | 1 | + // +---+---+---+---+---+---+---+---+---+---+ + + LONGS_EQUAL(100, hist.mov_quantile(1.0)); + LONGS_EQUAL(80, hist.mov_quantile(0.7)); + LONGS_EQUAL(70, hist.mov_quantile(0.4)); + LONGS_EQUAL(40, hist.mov_quantile(0.1)); +} + } // namespace stat } // namespace roc