diff --git a/api/nodes.go b/api/nodes.go index bfed5d8eb..bf7709fea 100644 --- a/api/nodes.go +++ b/api/nodes.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" ) @@ -673,9 +674,9 @@ func (v *StatValue) String() string { case v.StringVal != nil: return *v.StringVal case v.FloatNumeratorVal != nil: - str := strconv.FormatFloat(*v.FloatNumeratorVal, 'f', -1, 64) + str := helper.FormatFloat(*v.FloatNumeratorVal, 3) if v.FloatDenominatorVal != nil { - str += " / " + strconv.FormatFloat(*v.FloatDenominatorVal, 'f', -1, 64) + str += " / " + helper.FormatFloat(*v.FloatDenominatorVal, 3) } if v.Unit != "" { diff --git a/api/resources.go b/api/resources.go index 767d82625..d2a1af965 100644 --- a/api/resources.go +++ b/api/resources.go @@ -172,7 +172,7 @@ type Attribute struct { func (a Attribute) String() string { switch { case a.FloatVal != nil: - str := strconv.FormatFloat(*a.FloatVal, 'f', -1, 64) + str := helper.FormatFloat(*a.FloatVal, 3) if a.Unit != "" { str += " " + a.Unit } diff --git a/helper/funcs.go b/helper/funcs.go index 89027b4cb..cf9cc3dae 100644 --- a/helper/funcs.go +++ b/helper/funcs.go @@ -4,6 +4,8 @@ import ( "crypto/sha512" "fmt" "regexp" + "strconv" + "strings" "time" multierror "github.com/hashicorp/go-multierror" @@ -344,3 +346,26 @@ func CheckHCLKeys(node ast.Node, valid []string) error { return result } + +// FormatFloat converts the floating-point number f to a string, +// after rounding it to the passed unit. +// +// Uses 'f' format (-ddd.dddddd, no exponent), and uses at most +// maxPrec digits after the decimal point. +func FormatFloat(f float64, maxPrec int) string { + v := strconv.FormatFloat(f, 'f', -1, 64) + + idx := strings.LastIndex(v, ".") + if idx == -1 { + return v + } + + sublen := idx + maxPrec + 1 + if sublen > len(v) { + sublen = len(v) + } + + return v[:sublen] + + return v +} diff --git a/helper/funcs_test.go b/helper/funcs_test.go index 774030be1..e9c9cdcd7 100644 --- a/helper/funcs_test.go +++ b/helper/funcs_test.go @@ -4,6 +4,8 @@ import ( "reflect" "sort" "testing" + + "github.com/stretchr/testify/require" ) func TestSliceStringIsSubset(t *testing.T) { @@ -87,3 +89,35 @@ func BenchmarkCleanEnvVar(b *testing.B) { CleanEnvVar(in, replacement) } } + +func TestFormatRoundedFloat(t *testing.T) { + cases := []struct { + input float64 + expected string + }{ + { + 1323, + "1323", + }, + { + 10.321, + "10.321", + }, + { + 100000.31324324, + "100000.313", + }, + { + 100000.3, + "100000.3", + }, + { + 0.7654321, + "0.765", + }, + } + + for _, c := range cases { + require.Equal(t, c.expected, FormatFloat(c.input, 3)) + } +}