@@ -182,9 +182,21 @@ func histogramQuantile(q float64, h *histogram.FloatHistogram) float64 {
182
182
var (
183
183
bucket histogram.Bucket [float64 ]
184
184
count float64
185
- it = h . AllBucketIterator ()
186
- rank = q * h . Count
185
+ it histogram. BucketIterator [ float64 ]
186
+ rank float64
187
187
)
188
+
189
+ // if there are NaN observations in the histogram (h.Sum is NaN), use the forward iterator
190
+ // if the q < 0.5, use the forward iterator
191
+ // if the q >= 0.5, use the reverse iterator
192
+ if math .IsNaN (h .Sum ) || q < 0.5 {
193
+ it = h .AllBucketIterator ()
194
+ rank = q * h .Count
195
+ } else {
196
+ it = h .AllReverseBucketIterator ()
197
+ rank = (1 - q ) * h .Count
198
+ }
199
+
188
200
for it .Next () {
189
201
bucket = it .At ()
190
202
count += bucket .Count
@@ -193,11 +205,12 @@ func histogramQuantile(q float64, h *histogram.FloatHistogram) float64 {
193
205
}
194
206
}
195
207
if bucket .Lower < 0 && bucket .Upper > 0 {
196
- if len (h .NegativeBuckets ) == 0 && len (h .PositiveBuckets ) > 0 {
208
+ switch {
209
+ case len (h .NegativeBuckets ) == 0 && len (h .PositiveBuckets ) > 0 :
197
210
// The result is in the zero bucket and the histogram has only
198
211
// positive buckets. So we consider 0 to be the lower bound.
199
212
bucket .Lower = 0
200
- } else if len (h .PositiveBuckets ) == 0 && len (h .NegativeBuckets ) > 0 {
213
+ case len (h .PositiveBuckets ) == 0 && len (h .NegativeBuckets ) > 0 :
201
214
// The result is in the zero bucket and the histogram has only
202
215
// negative buckets. So we consider 0 to be the upper bound.
203
216
bucket .Upper = 0
@@ -216,7 +229,17 @@ func histogramQuantile(q float64, h *histogram.FloatHistogram) float64 {
216
229
return bucket .Upper
217
230
}
218
231
219
- rank -= count - bucket .Count
232
+ // NaN observations increase h.Count but not the total number of
233
+ // observations in the buckets. Therefore, we have to use the forward
234
+ // iterator to find percentiles. We recognize histograms containing NaN
235
+ // observations by checking if their h.Sum is NaN.
236
+ if math .IsNaN (h .Sum ) || q < 0.5 {
237
+ rank -= count - bucket .Count
238
+ } else {
239
+ rank = count - rank
240
+ }
241
+
242
+ // TODO(codesome): Use a better estimation than linear.
220
243
return bucket .Lower + (bucket .Upper - bucket .Lower )* (rank / bucket .Count )
221
244
}
222
245
0 commit comments