diff --git a/docs/querying/functions.md b/docs/querying/functions.md index 33740ac4ab..1de8bb2aa9 100644 --- a/docs/querying/functions.md +++ b/docs/querying/functions.md @@ -192,7 +192,7 @@ bucket. Otherwise, the upper bound of the lowest bucket is returned for quantiles located in the lowest bucket. If `b` has 0 observations, `NaN` is returned. If `b` contains fewer than two buckets, -`NaN` is returned. For φ < 0, `-Inf` is returned. For φ > 1, `+Inf` is returned. +`NaN` is returned. For φ < 0, `-Inf` is returned. For φ > 1, `+Inf` is returned. For φ = `NaN`, `NaN` is returned. ## `holt_winters()` @@ -456,4 +456,4 @@ The following are useful for converting between degrees and radians: - `deg(v instant-vector)`: converts radians to degrees for all elements in `v`. - `pi()`: returns pi. -- `rad(v instant-vector)`: converts degrees to radians for all elements in `v`. \ No newline at end of file +- `rad(v instant-vector)`: converts degrees to radians for all elements in `v`. diff --git a/docs/querying/operators.md b/docs/querying/operators.md index a0491bdbeb..9f35e0c153 100644 --- a/docs/querying/operators.md +++ b/docs/querying/operators.md @@ -241,7 +241,7 @@ vector. `by` and `without` are only used to bucket the input vector. `quantile` calculates the φ-quantile, the value that ranks at number φ*N among the N metric values of the dimensions aggregated over. φ is provided as the aggregation parameter. For example, `quantile(0.5, ...)` calculates the median, -`quantile(0.95, ...)` the 95th percentile. +`quantile(0.95, ...)` the 95th percentile. For φ = `NaN`, `NaN` is returned. For φ < 0, `-Inf` is returned. For φ > 1, `+Inf` is returned. Example: diff --git a/promql/quantile.go b/promql/quantile.go index e2de98840c..a3abf68dd0 100644 --- a/promql/quantile.go +++ b/promql/quantile.go @@ -67,10 +67,15 @@ type metricWithBuckets struct { // // If the highest bucket is not +Inf, NaN is returned. // +// If q==NaN, NaN is returned. +// // If q<0, -Inf is returned. // // If q>1, +Inf is returned. func bucketQuantile(q float64, buckets buckets) float64 { + if math.IsNaN(q) { + return math.NaN() + } if q < 0 { return math.Inf(-1) } @@ -182,10 +187,11 @@ func ensureMonotonic(buckets buckets) { // // The Vector will be sorted. // If 'values' has zero elements, NaN is returned. +// If q==NaN, NaN is returned. // If q<0, -Inf is returned. // If q>1, +Inf is returned. func quantile(q float64, values vectorByValueHeap) float64 { - if len(values) == 0 { + if len(values) == 0 || math.IsNaN(q) { return math.NaN() } if q < 0 { diff --git a/promql/testdata/aggregators.test b/promql/testdata/aggregators.test index 220c5edce1..8709b393b2 100644 --- a/promql/testdata/aggregators.test +++ b/promql/testdata/aggregators.test @@ -399,6 +399,11 @@ eval instant at 1m quantile without(point)((scalar(foo)), data) {test="three samples"} 1.6 {test="uneven samples"} 2.8 +eval instant at 1m quantile without(point)(NaN, data) + {test="two samples"} NaN + {test="three samples"} NaN + {test="uneven samples"} NaN + # Tests for group. clear diff --git a/promql/testdata/histograms.test b/promql/testdata/histograms.test index 508f1eface..f30c07e7b3 100644 --- a/promql/testdata/histograms.test +++ b/promql/testdata/histograms.test @@ -60,6 +60,11 @@ eval instant at 50m histogram_quantile(1.01, testhistogram_bucket) {start="positive"} +Inf {start="negative"} +Inf +# Quantile invalid. +eval instant at 50m histogram_quantile(NaN, testhistogram_bucket) + {start="positive"} NaN + {start="negative"} NaN + # Quantile value in lowest bucket, which is positive. eval instant at 50m histogram_quantile(0, testhistogram_bucket{start="positive"}) {start="positive"} 0