mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-25 05:34:05 -08:00
Fix issue where summation of +/- infinity returns NaN instead of infinity
Signed-off-by: Charles Korn <charles.korn@grafana.com>
This commit is contained in:
parent
c5040c5ea9
commit
fd6bdf5230
|
@ -950,10 +950,14 @@ func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||||
|
|
||||||
func kahanSumInc(inc, sum, c float64) (newSum, newC float64) {
|
func kahanSumInc(inc, sum, c float64) (newSum, newC float64) {
|
||||||
t := sum + inc
|
t := sum + inc
|
||||||
|
switch {
|
||||||
|
case math.IsInf(t, 0):
|
||||||
|
c = 0
|
||||||
|
|
||||||
// Using Neumaier improvement, swap if next term larger than sum.
|
// Using Neumaier improvement, swap if next term larger than sum.
|
||||||
if math.Abs(sum) >= math.Abs(inc) {
|
case math.Abs(sum) >= math.Abs(inc):
|
||||||
c += (sum - t) + inc
|
c += (sum - t) + inc
|
||||||
} else {
|
default:
|
||||||
c += (inc - t) + sum
|
c += (inc - t) + sum
|
||||||
}
|
}
|
||||||
return t, c
|
return t, c
|
||||||
|
|
81
promql/functions_internal_test.go
Normal file
81
promql/functions_internal_test.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2015 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package promql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKahanSumInc(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
first float64
|
||||||
|
second float64
|
||||||
|
expected float64
|
||||||
|
}{
|
||||||
|
"+Inf + anything = +Inf": {
|
||||||
|
first: math.Inf(1),
|
||||||
|
second: 2.0,
|
||||||
|
expected: math.Inf(1),
|
||||||
|
},
|
||||||
|
"-Inf + anything = -Inf": {
|
||||||
|
first: math.Inf(-1),
|
||||||
|
second: 2.0,
|
||||||
|
expected: math.Inf(-1),
|
||||||
|
},
|
||||||
|
"+Inf + -Inf = NaN": {
|
||||||
|
first: math.Inf(1),
|
||||||
|
second: math.Inf(-1),
|
||||||
|
expected: math.NaN(),
|
||||||
|
},
|
||||||
|
"NaN + anything = NaN": {
|
||||||
|
first: math.NaN(),
|
||||||
|
second: 2,
|
||||||
|
expected: math.NaN(),
|
||||||
|
},
|
||||||
|
"NaN + Inf = NaN": {
|
||||||
|
first: math.NaN(),
|
||||||
|
second: math.Inf(1),
|
||||||
|
expected: math.NaN(),
|
||||||
|
},
|
||||||
|
"NaN + -Inf = NaN": {
|
||||||
|
first: math.NaN(),
|
||||||
|
second: math.Inf(-1),
|
||||||
|
expected: math.NaN(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runTest := func(t *testing.T, a, b, expected float64) {
|
||||||
|
t.Run(fmt.Sprintf("%v + %v = %v", a, b, expected), func(t *testing.T) {
|
||||||
|
sum, c := kahanSumInc(b, a, 0)
|
||||||
|
result := sum + c
|
||||||
|
|
||||||
|
if math.IsNaN(expected) {
|
||||||
|
require.Truef(t, math.IsNaN(result), "expected result to be NaN, but got %v (from %v + %v)", result, sum, c)
|
||||||
|
} else {
|
||||||
|
require.Equalf(t, expected, result, "expected result to be %v, but got %v (from %v + %v)", expected, result, sum, c)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
runTest(t, testCase.first, testCase.second, testCase.expected)
|
||||||
|
runTest(t, testCase.second, testCase.first, testCase.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
29
promql/promqltest/testdata/aggregators.test
vendored
29
promql/promqltest/testdata/aggregators.test
vendored
|
@ -511,10 +511,39 @@ load 10s
|
||||||
data{test="ten",point="b"} 8
|
data{test="ten",point="b"} 8
|
||||||
data{test="ten",point="c"} 1e+100
|
data{test="ten",point="c"} 1e+100
|
||||||
data{test="ten",point="d"} -1e100
|
data{test="ten",point="d"} -1e100
|
||||||
|
data{test="pos_inf",group="1",point="a"} Inf
|
||||||
|
data{test="pos_inf",group="1",point="b"} 2
|
||||||
|
data{test="pos_inf",group="2",point="a"} 2
|
||||||
|
data{test="pos_inf",group="2",point="b"} Inf
|
||||||
|
data{test="neg_inf",group="1",point="a"} -Inf
|
||||||
|
data{test="neg_inf",group="1",point="b"} 2
|
||||||
|
data{test="neg_inf",group="2",point="a"} 2
|
||||||
|
data{test="neg_inf",group="2",point="b"} -Inf
|
||||||
|
data{test="inf_inf",point="a"} Inf
|
||||||
|
data{test="inf_inf",point="b"} -Inf
|
||||||
|
data{test="nan",group="1",point="a"} NaN
|
||||||
|
data{test="nan",group="1",point="b"} 2
|
||||||
|
data{test="nan",group="2",point="a"} 2
|
||||||
|
data{test="nan",group="2",point="b"} NaN
|
||||||
|
|
||||||
eval instant at 1m sum(data{test="ten"})
|
eval instant at 1m sum(data{test="ten"})
|
||||||
{} 10
|
{} 10
|
||||||
|
|
||||||
|
eval instant at 1m sum by (group) (data{test="pos_inf"})
|
||||||
|
{group="1"} Inf
|
||||||
|
{group="2"} Inf
|
||||||
|
|
||||||
|
eval instant at 1m sum by (group) (data{test="neg_inf"})
|
||||||
|
{group="1"} -Inf
|
||||||
|
{group="2"} -Inf
|
||||||
|
|
||||||
|
eval instant at 1m sum(data{test="inf_inf"})
|
||||||
|
{} NaN
|
||||||
|
|
||||||
|
eval instant at 1m sum by (group) (data{test="nan"})
|
||||||
|
{group="1"} NaN
|
||||||
|
{group="2"} NaN
|
||||||
|
|
||||||
clear
|
clear
|
||||||
|
|
||||||
# Test that aggregations are deterministic.
|
# Test that aggregations are deterministic.
|
||||||
|
|
|
@ -355,10 +355,10 @@ load 10m
|
||||||
histogram_stddev_stdvar_7 {{schema:3 count:7 sum:Inf z_bucket:1 buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ] n_buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]}}x1
|
histogram_stddev_stdvar_7 {{schema:3 count:7 sum:Inf z_bucket:1 buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ] n_buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]}}x1
|
||||||
|
|
||||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_7)
|
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_7)
|
||||||
{} NaN
|
{} Inf
|
||||||
|
|
||||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_7)
|
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_7)
|
||||||
{} NaN
|
{} Inf
|
||||||
|
|
||||||
# Apply quantile function to histogram with all positive buckets with zero bucket.
|
# Apply quantile function to histogram with all positive buckets with zero bucket.
|
||||||
load 10m
|
load 10m
|
||||||
|
|
Loading…
Reference in a new issue