lib/decimal: properly calibrate scale for blocks with Inf values

See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/805
This commit is contained in:
Aliaksandr Valialkin 2020-10-05 14:48:02 +03:00
parent 3e0c473cc9
commit d448e07546
2 changed files with 25 additions and 19 deletions

View file

@ -36,6 +36,9 @@ func CalibrateScale(a []int64, ae int16, b []int64, be int16) (e int16) {
}
upExp -= downExp
for i, v := range a {
if v == vInfPos || v == vInfNeg {
continue
}
adjExp := upExp
for adjExp > 0 {
v *= 10
@ -45,6 +48,9 @@ func CalibrateScale(a []int64, ae int16, b []int64, be int16) (e int16) {
}
if downExp > 0 {
for i, v := range b {
if v == vInfPos || v == vInfNeg {
continue
}
adjExp := downExp
for adjExp > 0 {
v /= 10
@ -188,9 +194,6 @@ func AppendFloatToDecimal(dst []int64, src []float64) ([]int64, int16) {
downExp := int16(0)
_ = ea[len(va)-1]
for i, v := range va {
if v == vInfPos || v == vInfNeg {
continue
}
exp := ea[i]
upExp := exp - minExp
maxUpExp := maxUpExponent(v)
@ -242,7 +245,7 @@ var vaeBufPool sync.Pool
const int64Max = int64(1<<63 - 1)
func maxUpExponent(v int64) int16 {
if v == 0 {
if v == 0 || v == vInfPos || v == vInfNeg {
// Any exponent allowed.
return 1024
}

View file

@ -131,14 +131,22 @@ func TestCalibrateScale(t *testing.T) {
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{500, 100}, 0, 0, []int64{vInfPos, 1200}, []int64{500, 100}, 0)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{500, 100}, 0, 2, []int64{vInfPos, 1200}, []int64{500e2, 100e2}, 0)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{500, 100}, 0, -2, []int64{vInfPos, 1200}, []int64{5, 1}, 0)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{3500, 100}, 0, -3, []int64{vInfPos, 1200}, []int64{3, 0}, 0)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{35, 1}, 0, 40, []int64{0, 0}, []int64{35e17, 1e17}, 23)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{35, 1}, 40, 0, []int64{vInfPos, 1200}, []int64{0, 0}, 40)
testCalibrateScale(t, []int64{vInfNeg, 1200}, []int64{35, 1}, 35, -5, []int64{vInfNeg, 1200}, []int64{0, 0}, 35)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{500, 100}, 0, -2, []int64{vInfPos, 12e4}, []int64{500, 100}, -2)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{3500, 100}, 0, -3, []int64{vInfPos, 12e5}, []int64{3500, 100}, -3)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{35, 1}, 0, 40, []int64{vInfPos, 0}, []int64{35e17, 1e17}, 23)
testCalibrateScale(t, []int64{vInfPos, 1200}, []int64{35, 1}, 40, 0, []int64{vInfPos, 12e17}, []int64{0, 0}, 25)
testCalibrateScale(t, []int64{vInfNeg, 1200}, []int64{35, 1}, 35, -5, []int64{vInfNeg, 12e17}, []int64{0, 0}, 20)
testCalibrateScale(t, []int64{vMax, vMin, 123}, []int64{100}, 0, 3, []int64{vMax, vMin, 123}, []int64{100e3}, 0)
testCalibrateScale(t, []int64{vMax, vMin, 123}, []int64{100}, 3, 0, []int64{vMax, vMin, 123}, []int64{0}, 3)
testCalibrateScale(t, []int64{vMax, vMin, 123}, []int64{100}, 0, 30, []int64{92233, -92233, 0}, []int64{100e16}, 14)
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/805
testCalibrateScale(t, []int64{123}, []int64{vInfPos}, 0, 0, []int64{123}, []int64{vInfPos}, 0)
testCalibrateScale(t, []int64{123, vInfPos}, []int64{vInfNeg}, 0, 0, []int64{123, vInfPos}, []int64{vInfNeg}, 0)
testCalibrateScale(t, []int64{123, vInfPos, vInfNeg}, []int64{456}, 0, 0, []int64{123, vInfPos, vInfNeg}, []int64{456}, 0)
testCalibrateScale(t, []int64{123, vInfPos, vInfNeg, 456}, []int64{}, 0, 0, []int64{123, vInfPos, vInfNeg, 456}, []int64{}, 0)
testCalibrateScale(t, []int64{123, vInfPos}, []int64{vInfNeg, 456}, 0, 0, []int64{123, vInfPos}, []int64{vInfNeg, 456}, 0)
testCalibrateScale(t, []int64{123, vInfPos}, []int64{vInfNeg, 456}, 0, 10, []int64{123, vInfPos}, []int64{vInfNeg, 456e10}, 0)
}
func testCalibrateScale(t *testing.T, a, b []int64, ae, be int16, aExpected, bExpected []int64, eExpected int16) {
@ -175,7 +183,7 @@ func testCalibrateScale(t *testing.T, a, b []int64, ae, be int16, aExpected, bEx
bCopy = append([]int64{}, b...)
e = CalibrateScale(bCopy, be, aCopy, ae)
if e != eExpected {
t.Fatalf("revers: unexpected e for a=%d, b=%d, ae=%d, be=%d; got %d; expecting %d", a, b, ae, be, e, eExpected)
t.Fatalf("reverse: unexpected e for a=%d, b=%d, ae=%d, be=%d; got %d; expecting %d", a, b, ae, be, e, eExpected)
}
if !reflect.DeepEqual(aCopy, aExpected) {
t.Fatalf("reverse: unexpected a for b=%d, ae=%d, be=%d; got\n%d; expecting\n%d", b, ae, be, aCopy, aExpected)
@ -193,18 +201,13 @@ func TestMaxUpExponent(t *testing.T) {
if e != eExpected {
t.Fatalf("unexpected e for v=%d; got %d; expecting %d", v, e, eExpected)
}
e = maxUpExponent(-v)
if e != eExpected {
t.Fatalf("unexpected e for v=%d; got %d; expecting %d", -v, e, eExpected)
}
}
f(vInfPos, 0)
f(vInfNeg, 0)
f(vInfPos, 1024)
f(vInfNeg, 1024)
f(vMin, 0)
f(vMax, 0)
f(0, 1024)
f(-1<<63, 0)
f((-1<<63)+1, 0)
f((1<<63)-1, 0)
f(1, 18)
f(12, 17)
f(123, 16)