lib/decimal: prevent exponent overflow when processing values close to zero

See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1114
This commit is contained in:
Aliaksandr Valialkin 2021-03-05 18:51:35 +02:00
parent 26cb6f8861
commit 175466bb41
3 changed files with 22 additions and 0 deletions

View file

@ -10,6 +10,7 @@
* FEATURE: vmauth: allow using regexp paths in `url_map`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1112) for details. * FEATURE: vmauth: allow using regexp paths in `url_map`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1112) for details.
* BUGFIX: vmagent: reduce memory usage when Kubernetes service discovery is used in big number of distinct jobs by sharing the cache. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1113 * BUGFIX: vmagent: reduce memory usage when Kubernetes service discovery is used in big number of distinct jobs by sharing the cache. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1113
* BUGFIX: prevent exponent overflow when processing extremely small values close to zero such as `2.964393875E-314`. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1114
# [v1.55.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.55.1) # [v1.55.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.55.1)

View file

@ -456,6 +456,13 @@ func positiveFloatToDecimalSlow(f float64) (int64, int16) {
prec = 1e15 prec = 1e15
} }
_, exp := math.Frexp(f) _, exp := math.Frexp(f)
// Bound the exponent according to https://en.wikipedia.org/wiki/Double-precision_floating-point_format
// This fixes the issue https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1114
if exp < -1022 {
exp = -1022
} else if exp > 1023 {
exp = 1023
}
scale = int16(float64(exp) * (math.Ln2 / math.Ln10)) scale = int16(float64(exp) * (math.Ln2 / math.Ln10))
f *= math.Pow10(-int(scale)) f *= math.Pow10(-int(scale))
} }

View file

@ -95,6 +95,20 @@ func TestPositiveFloatToDecimal(t *testing.T) {
f(0.001130435, 1130435, -9) f(0.001130435, 1130435, -9)
f(vInfPos, 9223372036854775, 3) f(vInfPos, 9223372036854775, 3)
f(vMax, 9223372036854775, 3) f(vMax, 9223372036854775, 3)
// Extreme cases. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1114
f(2.964393875e-100, 2964393875, -109)
f(2.964393875e-309, 2964393875, -318)
f(2.964393875e-314, 296439387505, -325)
f(2.964393875e-315, 2964393875047, -327)
f(2.964393875e-320, 296439387505, -331)
f(2.964393875e-324, 494065645841, -335)
f(2.964393875e-325, 0, 1)
f(2.964393875e+307, 2964393875, 298)
f(9.964393875e+307, 9964393875, 298)
f(1.064393875e+308, 1064393875, 299)
f(1.797393875e+308, 1797393875, 299)
} }
func TestAppendDecimalToFloat(t *testing.T) { func TestAppendDecimalToFloat(t *testing.T) {