From 3ded2e09ee1b5e399e46206e02ac46bae2072dc4 Mon Sep 17 00:00:00 2001 From: Chris <24967655+ProfessorMc@users.noreply.github.com> Date: Mon, 26 Aug 2019 22:57:02 -0500 Subject: [PATCH] Fix float64 truncation error (#293) Don't truncate float64 representation on marashaling. Fixes https://github.com/pelletier/go-toml/issues/289 --- marshal_OrderPreserve_test.toml | 1 + marshal_test.go | 6 ++++-- marshal_test.toml | 1 + tomltree_write.go | 19 ++++++++++++++----- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/marshal_OrderPreserve_test.toml b/marshal_OrderPreserve_test.toml index 9d68b59..792b72e 100644 --- a/marshal_OrderPreserve_test.toml +++ b/marshal_OrderPreserve_test.toml @@ -27,6 +27,7 @@ title = "TOML Marshal Testing" uint = 5001 bool = true float = 123.4 + float64 = 123.456782132399 int = 5000 string = "Bite me" date = 1979-05-27T07:32:00Z diff --git a/marshal_test.go b/marshal_test.go index 45c0e92..c33e748 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -135,7 +135,8 @@ type testMapDoc struct { type testDocBasics struct { Uint uint `toml:"uint"` Bool bool `toml:"bool"` - Float float32 `toml:"float"` + Float32 float32 `toml:"float"` + Float64 float64 `toml:"float64"` Int int `toml:"int"` String *string `toml:"string"` Date time.Time `toml:"date"` @@ -174,7 +175,8 @@ var docData = testDoc{ Basics: testDocBasics{ Bool: true, Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), - Float: 123.4, + Float32: 123.4, + Float64: 123.456782132399, Int: 5000, Uint: 5001, String: &biteMe, diff --git a/marshal_test.toml b/marshal_test.toml index 1c5f98e..ba5e110 100644 --- a/marshal_test.toml +++ b/marshal_test.toml @@ -4,6 +4,7 @@ title = "TOML Marshal Testing" bool = true date = 1979-05-27T07:32:00Z float = 123.4 + float64 = 123.456782132399 int = 5000 string = "Bite me" uint = 5001 diff --git a/tomltree_write.go b/tomltree_write.go index 9381a88..ee46773 100644 --- a/tomltree_write.go +++ b/tomltree_write.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "math" + "math/big" "reflect" "sort" "strconv" @@ -106,12 +107,20 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen case int64: return strconv.FormatInt(value, 10), nil case float64: - // Ensure a round float does contain a decimal point. Otherwise feeding - // the output back to the parser would convert to an integer. - if math.Trunc(value) == value { - return strings.ToLower(strconv.FormatFloat(value, 'f', 1, 32)), nil + // Default bit length is full 64 + bits := 64 + // Float panics if nan is used + if !math.IsNaN(value) { + // if 32 bit accuracy is enough to exactly show, use 32 + _, acc := big.NewFloat(value).Float32() + if acc == big.Exact { + bits = 32 + } } - return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil + if math.Trunc(value) == value { + return strings.ToLower(strconv.FormatFloat(value, 'f', 1, bits)), nil + } + return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil case string: if tv.multiline { return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil