Skip to content

Commit f0e7b87

Browse files
committed
[benchmark] Round quantile idx to nearest or even
Explicitly use round-half-to-even rounding algorithm to match the behavior of numpy's quantile(interpolation='nearest') and quantile estimate type R-3, SAS-2. See: https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
1 parent 9bd599a commit f0e7b87

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

benchmark/scripts/compare_perf_tests.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class `ReportFormatter` creates the test comparison report in specified format.
3434
import sys
3535
from bisect import bisect, bisect_left, bisect_right
3636
from collections import namedtuple
37+
from decimal import Decimal, ROUND_HALF_EVEN
3738
from math import sqrt
3839

3940

@@ -141,24 +142,32 @@ def max(self):
141142
"""Maximum sampled value."""
142143
return self.samples[-1].runtime
143144

144-
def _quantile_index(self, q, i):
145-
"""Return index of the element nearest to the i-th q-quantile."""
146-
return int(round((self.count - 1) / float(q) * float(i)))
145+
def quantile(self, q):
146+
"""Return runtime of a sample nearest to the quantile.
147+
148+
Explicitly uses round-half-to-even rounding algorithm to match the
149+
behavior of numpy's quantile(interpolation='nearest') and quantile
150+
estimate type R-3, SAS-2. See:
151+
https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
152+
"""
153+
index = int(Decimal((self.count - 1) * Decimal(q))
154+
.quantize(0, ROUND_HALF_EVEN))
155+
return self.samples[index].runtime
147156

148157
@property
149158
def median(self):
150159
"""Median sampled value."""
151-
return self.samples[self._quantile_index(2, 1)].runtime
160+
return self.quantile(0.5)
152161

153162
@property
154163
def q1(self):
155164
"""First Quartile (25th Percentile)."""
156-
return self.samples[self._quantile_index(4, 1)].runtime
165+
return self.quantile(0.25)
157166

158167
@property
159168
def q3(self):
160169
"""Third Quartile (75th Percentile)."""
161-
return self.samples[self._quantile_index(4, 3)].runtime
170+
return self.quantile(0.75)
162171

163172
@property
164173
def iqr(self):

benchmark/scripts/test_compare_perf_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ def test_computes_five_number_summary(self):
7575
self.samples, (1000, 1000, 1000, 1000, 1000))
7676
self.samples.add(Sample(2, 1, 1100))
7777
self.assertEqualFiveNumberSummary(
78-
self.samples, (1000, 1000, 1100, 1100, 1100))
78+
self.samples, (1000, 1000, 1000, 1100, 1100))
7979
self.samples.add(Sample(3, 1, 1050))
8080
self.assertEqualFiveNumberSummary(
81-
self.samples, (1000, 1050, 1050, 1100, 1100))
81+
self.samples, (1000, 1000, 1050, 1100, 1100))
8282
self.samples.add(Sample(4, 1, 1025))
8383
self.assertEqualFiveNumberSummary(
8484
self.samples, (1000, 1025, 1050, 1050, 1100))

benchmark/utils/DriverUtils.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@ struct BenchResults {
3232
}
3333

3434
/// Return sample at index nearest to the `quantile`.
35+
///
36+
/// Explicitly uses round-half-to-even rounding algorithm to match the
37+
/// behavior of numpy's quantile(interpolation='nearest') and quantile
38+
/// estimate type R-3, SAS-2. See:
39+
/// https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
3540
subscript(_ quantile: Double) -> T {
36-
let index = Int((Double(samples.count - 1) * quantile).rounded())
41+
let index = Int(
42+
(Double(samples.count - 1) * quantile).rounded(.toNearestOrEven))
3743
return samples[index]
3844
}
3945

0 commit comments

Comments
 (0)