Write out full resolution floats in flatbuffer to JSON

It turns out that we were missing a 1--2 digits of precision
necessary to fully represent floats/doubles. In most cases where we
would care about bit-perfect

This moves all of our flatbuffer->JSON conversion to use
std::format/std::to_chars, which specifically guarantee that you will be
able to read the number back fully, while truncating numbers reasonably
so that e.g. 0.1 actually renders reasonably to the human eye.

In doing so, this also reduces some of the inconsistencies between the
two FlatbufferToJson methods.

This forces updates in a variety of tests that make use of this code and
which check for exactly identical serialized JSON values.

Change-Id: Idbf6a5614043ce4d6c02f3104991e30fdca23334
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/fast_string_builder.cc b/aos/fast_string_builder.cc
index 0445535..00fe001 100644
--- a/aos/fast_string_builder.cc
+++ b/aos/fast_string_builder.cc
@@ -1,5 +1,7 @@
 #include "aos/fast_string_builder.h"
 
+#include <charconv>
+
 namespace aos {
 
 FastStringBuilder::FastStringBuilder(std::size_t initial_size) {
@@ -30,20 +32,22 @@
 
 void FastStringBuilder::Append(float val) {
   std::size_t index = str_.size();
-  Resize(17);
-  int result = absl::SNPrintF(str_.data() + index, 17, "%.6g", val);
-  PCHECK(result != -1);
-  CHECK(result < 17);
-  str_.resize(index + result);
+  constexpr std::size_t kMaxSize = 17;
+  Resize(kMaxSize);
+  const std::to_chars_result result =
+      std::to_chars(str_.data() + index, str_.data() + index + kMaxSize, val);
+  CHECK(result.ec == std::errc()) << std::make_error_code(result.ec).message();
+  str_.resize(result.ptr - str_.data());
 }
 
 void FastStringBuilder::Append(double val) {
   std::size_t index = str_.size();
-  Resize(25);
-  int result = absl::SNPrintF(str_.data() + index, 25, "%.15g", val);
-  PCHECK(result != -1);
-  CHECK(result < 25);
-  str_.resize(index + result);
+  constexpr std::size_t kMaxSize = 25;
+  Resize(kMaxSize);
+  const std::to_chars_result result =
+      std::to_chars(str_.data() + index, str_.data() + index + kMaxSize, val);
+  CHECK(result.ec == std::errc()) << std::make_error_code(result.ec).message();
+  str_.resize(result.ptr - str_.data());
 }
 
 void FastStringBuilder::AppendChar(char val) {
diff --git a/aos/flatbuffer_introspection_test.cc b/aos/flatbuffer_introspection_test.cc
index 54c6f18..66de6d9 100644
--- a/aos/flatbuffer_introspection_test.cc
+++ b/aos/flatbuffer_introspection_test.cc
@@ -61,8 +61,8 @@
 
   std::string out = FlatbufferToJson(schema_, builder.GetBufferPointer());
 
-  EXPECT_EQ(out,
-            "{ \"foo_double\": 0.555555555555556, \"foo_float\": 0.333333 }");
+  EXPECT_EQ(
+      out, "{ \"foo_double\": 0.5555555555555556, \"foo_float\": 0.33333334 }");
 }
 
 TEST_F(FlatbufferIntrospectionTest, NanFloatTest) {
@@ -129,18 +129,19 @@
 
   std::string out = FlatbufferToJson(schema_, builder.GetBufferPointer());
 
-  EXPECT_EQ(out,
-            "{ \"vector_foo_bool\": [ true, false, true, false ], "
-            "\"vector_foo_byte\": [ -3, -2, -1, 0, 1, 2, 3 ], "
-            "\"vector_foo_double\": [ 0, 0.111111111111111, 0.222222222222222, "
-            "0.333333333333333 ], \"vector_foo_float\": [ 0, 0.111111, "
-            "0.222222, 0.333333 ], \"vector_foo_int\": [ -300, -200, -100, 0, "
-            "100, 200, 300 ], \"vector_foo_long\": [ -3000, -2000, -1000, 0, "
-            "1000, 2000, 3000 ], \"vector_foo_short\": [ -30, -20, -10, 0, 10, "
-            "20, 30 ], \"vector_foo_ubyte\": [ 0, 1, 2, 3, 4, 5, 6 ], "
-            "\"vector_foo_uint\": [ 0, 100, 200, 300, 400, 500, 600 ], "
-            "\"vector_foo_ulong\": [ 0, 1000, 2000, 3000, 4000, 5000, 6000 ], "
-            "\"vector_foo_ushort\": [ 0, 10, 20, 30, 40, 50, 60 ] }");
+  EXPECT_EQ(
+      out,
+      "{ \"vector_foo_bool\": [ true, false, true, false ], "
+      "\"vector_foo_byte\": [ -3, -2, -1, 0, 1, 2, 3 ], \"vector_foo_double\": "
+      "[ 0, 0.1111111111111111, 0.2222222222222222, 0.3333333333333333 ], "
+      "\"vector_foo_float\": [ 0, 0.11111111, 0.22222222, 0.33333334 ], "
+      "\"vector_foo_int\": [ -300, -200, -100, 0, 100, 200, 300 ], "
+      "\"vector_foo_long\": [ -3000, -2000, -1000, 0, 1000, 2000, 3000 ], "
+      "\"vector_foo_short\": [ -30, -20, -10, 0, 10, 20, 30 ], "
+      "\"vector_foo_ubyte\": [ 0, 1, 2, 3, 4, 5, 6 ], \"vector_foo_uint\": [ "
+      "0, 100, 200, 300, 400, 500, 600 ], \"vector_foo_ulong\": [ 0, 1000, "
+      "2000, 3000, 4000, 5000, 6000 ], \"vector_foo_ushort\": [ 0, 10, 20, 30, "
+      "40, 50, 60 ] }");
 }
 
 TEST_F(FlatbufferIntrospectionTest, StringTest) {
@@ -463,13 +464,12 @@
   std::string out = FlatbufferToJson(schema_, builder.GetBufferPointer(),
                                      {.multi_line = true});
 
-  EXPECT_EQ(out,
-            "{\n"
-            "  \"vector_foo_double\": [ 0, 0.111111111111111, "
-            "0.222222222222222, 0.333333333333333 ],\n"
-            "  \"vector_foo_float\": [ 0, 0.111111, 0.222222, 0.333333 ],\n"
-            "  \"vector_foo_int\": [ -300, -200, -100, 0, 100, 200, 300 ]\n"
-            "}");
+  EXPECT_EQ(
+      out,
+      "{\n  \"vector_foo_double\": [ 0, 0.1111111111111111, "
+      "0.2222222222222222, 0.3333333333333333 ],\n  \"vector_foo_float\": [ 0, "
+      "0.11111111, 0.22222222, 0.33333334 ],\n  \"vector_foo_int\": [ -300, "
+      "-200, -100, 0, 100, 200, 300 ]\n}");
 }
 
 // Tests that a nullptr buffer prints nullptr.
diff --git a/aos/flatbuffer_merge_test.cc b/aos/flatbuffer_merge_test.cc
index a2ac088..6bae5c4 100644
--- a/aos/flatbuffer_merge_test.cc
+++ b/aos/flatbuffer_merge_test.cc
@@ -375,10 +375,10 @@
   JsonMerge("{ \"foo_ulong\": 5 }", "{ \"foo_ulong\": 7 }",
             "{ \"foo_ulong\": 7 }");
 
-  JsonMerge("{ \"foo_float\": 5.0 }", "{ \"foo_float\": 7.1 }",
+  JsonMerge("{ \"foo_float\": 5 }", "{ \"foo_float\": 7.1 }",
             "{ \"foo_float\": 7.1 }");
 
-  JsonMerge("{ \"foo_double\": 5.0 }", "{ \"foo_double\": 7.1 }",
+  JsonMerge("{ \"foo_double\": 5 }", "{ \"foo_double\": 7.1 }",
             "{ \"foo_double\": 7.1 }");
 }
 
@@ -424,9 +424,9 @@
             "{ \"vector_foo_ulong\": [ 3, 1, 3, 2 ] }",
             "{ \"vector_foo_ulong\": [ 9, 7, 1, 3, 1, 3, 2 ] }");
 
-  JsonMerge("{ \"vector_foo_float\": [ 9.0, 7.0, 1.0 ] }",
-            "{ \"vector_foo_float\": [ -3.0, 1.3, 3.0, 2.0 ] }",
-            "{ \"vector_foo_float\": [ 9.0, 7.0, 1.0, -3.0, 1.3, 3.0, 2.0 ] }");
+  JsonMerge("{ \"vector_foo_float\": [ 9, 7, 1 ] }",
+            "{ \"vector_foo_float\": [ -3, 1.3, 3, 2 ] }",
+            "{ \"vector_foo_float\": [ 9, 7, 1, -3, 1.3, 3, 2 ] }");
 
   JsonMerge(
       "{ \"vector_foo_string\": [ \"9\", \"7\", \"1 \" ] }",
diff --git a/aos/flatbuffers/static_flatbuffers_fuzz_test.cc b/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
index fb1b3e1..755dd57 100644
--- a/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
+++ b/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
@@ -74,7 +74,7 @@
       },
       {
           "",
-          "\"substruct\": {\n  \"x\": 971.0,\n  \"y\": 123.0\n }",
+          "\"substruct\": {\n  \"x\": 971,\n  \"y\": 123\n }",
       },
       {
           "",
@@ -95,44 +95,44 @@
           "\"vector_of_structs\": [\n  \n ]",
           R"json("vector_of_structs": [
   {
-   "x": 1.0,
-   "y": 2.0
+   "x": 1,
+   "y": 2
   }
  ])json",
           R"json("vector_of_structs": [
   {
-   "x": 1.0,
-   "y": 2.0
+   "x": 1,
+   "y": 2
   },
   {
-   "x": 3.0,
-   "y": 4.0
+   "x": 3,
+   "y": 4
   },
   {
-   "x": 5.0,
-   "y": 6.0
+   "x": 5,
+   "y": 6
   }
  ])json",
           R"json("vector_of_structs": [
   {
-   "x": 1.0,
-   "y": 2.0
+   "x": 1,
+   "y": 2
   },
   {
-   "x": 3.0,
-   "y": 4.0
+   "x": 3,
+   "y": 4
   },
   {
-   "x": 5.0,
-   "y": 6.0
+   "x": 5,
+   "y": 6
   },
   {
-   "x": 7.0,
-   "y": 8.0
+   "x": 7,
+   "y": 8
   },
   {
-   "x": 9.0,
-   "y": 10.0
+   "x": 9,
+   "y": 10
   }
  ])json",
       },
diff --git a/aos/flatbuffers/static_flatbuffers_test.cc b/aos/flatbuffers/static_flatbuffers_test.cc
index 1846540..26dfc50 100644
--- a/aos/flatbuffers/static_flatbuffers_test.cc
+++ b/aos/flatbuffers/static_flatbuffers_test.cc
@@ -211,7 +211,7 @@
     CHECK(builder.AsFlatbufferSpan().Verify());
     EXPECT_EQ(123, object->AsFlatbuffer().foo());
     EXPECT_EQ(971, object->AsFlatbuffer().baz());
-    EXPECT_EQ(R"json({ "foo": 123, "baz": 971.0 })json",
+    EXPECT_EQ(R"json({ "foo": 123, "baz": 971 })json",
               aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
     TestMemory(builder.buffer());
   }
@@ -308,8 +308,8 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  }
 })json",
         aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
@@ -333,8 +333,8 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
@@ -373,24 +373,24 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
  },
  "vector_of_structs": [
   {
-   "x": 48.0,
-   "y": 67.0
+   "x": 48,
+   "y": 67
   },
   {
-   "x": 118.0,
-   "y": 148.0
+   "x": 118,
+   "y": 148
   },
   {
-   "x": 971.0,
-   "y": 973.0
+   "x": 971,
+   "y": 973
   }
  ]
 })json",
@@ -420,24 +420,24 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
  },
  "vector_of_structs": [
   {
-   "x": 48.0,
-   "y": 67.0
+   "x": 48,
+   "y": 67
   },
   {
-   "x": 118.0,
-   "y": 148.0
+   "x": 118,
+   "y": 148
   },
   {
-   "x": 971.0,
-   "y": 973.0
+   "x": 971,
+   "y": 973
   }
  ],
  "vector_of_tables": [
@@ -469,24 +469,24 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
  },
  "vector_of_structs": [
   {
-   "x": 48.0,
-   "y": 67.0
+   "x": 48,
+   "y": 67
   },
   {
-   "x": 118.0,
-   "y": 148.0
+   "x": 118,
+   "y": 148
   },
   {
-   "x": 971.0,
-   "y": 973.0
+   "x": 971,
+   "y": 973
   }
  ],
  "vector_of_tables": [
@@ -526,8 +526,8 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
@@ -537,16 +537,16 @@
  ],
  "vector_of_structs": [
   {
-   "x": 48.0,
-   "y": 67.0
+   "x": 48,
+   "y": 67
   },
   {
-   "x": 118.0,
-   "y": 148.0
+   "x": 118,
+   "y": 148
   },
   {
-   "x": 971.0,
-   "y": 973.0
+   "x": 971,
+   "y": 973
   }
  ],
  "vector_of_tables": [
@@ -592,8 +592,8 @@
   "D"
  ],
  "substruct": {
-  "x": 971.0,
-  "y": 254.0
+  "x": 971,
+  "y": 254
  },
  "subtable": {
   "foo": 1234
@@ -603,16 +603,16 @@
  ],
  "vector_of_structs": [
   {
-   "x": 48.0,
-   "y": 67.0
+   "x": 48,
+   "y": 67
   },
   {
-   "x": 118.0,
-   "y": 148.0
+   "x": 118,
+   "y": 148
   },
   {
-   "x": 971.0,
-   "y": 973.0
+   "x": 971,
+   "y": 973
   }
  ],
  "vector_of_tables": [
@@ -718,8 +718,8 @@
   1
  ],
  "substruct": {
-  "x": 2.0,
-  "y": 3.0
+  "x": 2,
+  "y": 3
  }
 })json",
         aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
@@ -737,8 +737,8 @@
   1
  ],
  "substruct": {
-  "x": 4.0,
-  "y": 5.0
+  "x": 4,
+  "y": 5
  }
 })json",
         aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
@@ -759,8 +759,8 @@
   1
  ],
  "substruct": {
-  "x": 4.0,
-  "y": 5.0
+  "x": 4,
+  "y": 5
  },
  "subtable": {
   "baz": 9.71
@@ -782,11 +782,11 @@
   1
  ],
  "substruct": {
-  "x": 4.0,
-  "y": 5.0
+  "x": 4,
+  "y": 5
  },
  "subtable": {
-  "baz": 16.780001
+  "baz": 16.78
  }
 })json",
         aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
@@ -1059,8 +1059,8 @@
   EXPECT_EQ(
       "{ \"scalar\": 971, \"vector_of_scalars\": [  ], \"string\": \"\", "
       "\"vector_of_strings\": [ \"971\" ], \"subtable\": { \"foo\": 0, "
-      "\"baz\": 0.0 }, \"vector_aligned\": [  ], \"vector_of_structs\": [ { "
-      "\"x\": 1.0, \"y\": 2.0 } ], \"vector_of_tables\": [  ], "
+      "\"baz\": 0 }, \"vector_aligned\": [  ], \"vector_of_structs\": [ { "
+      "\"x\": 1, \"y\": 2 } ], \"vector_of_tables\": [  ], "
       "\"unspecified_length_vector\": [  ], \"unspecified_length_string\": "
       "\"\", \"unspecified_length_vector_of_strings\": [  ] }",
       aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
diff --git a/aos/flatbuffers/test_dir/type_coverage.json b/aos/flatbuffers/test_dir/type_coverage.json
index 6d2bb16..ec88cbf 100644
--- a/aos/flatbuffers/test_dir/type_coverage.json
+++ b/aos/flatbuffers/test_dir/type_coverage.json
@@ -130,7 +130,7 @@
   55
  ],
  "vector_foo_float": [
-  21.0,
+  21,
   3.4,
   5.5
  ],
@@ -195,16 +195,16 @@
  },
  "vector_foo_struct_scalars": [
   {
-   "foo_float": 1.0,
-   "foo_double": 2.0,
+   "foo_float": 1,
+   "foo_double": 2,
    "foo_int32": 3,
    "foo_uint32": 4,
    "foo_int64": 5,
    "foo_uint64": 6
   },
   {
-   "foo_float": 7.0,
-   "foo_double": 8.0,
+   "foo_float": 7,
+   "foo_double": 8,
    "foo_int32": 9,
    "foo_uint32": 10,
    "foo_int64": 11,
diff --git a/aos/json_to_flatbuffer_test.cc b/aos/json_to_flatbuffer_test.cc
index 7c69acd..720c55d 100644
--- a/aos/json_to_flatbuffer_test.cc
+++ b/aos/json_to_flatbuffer_test.cc
@@ -93,10 +93,15 @@
   EXPECT_TRUE(JsonAndBack("{ \"foo_long\": 5 }"));
   EXPECT_TRUE(JsonAndBack("{ \"foo_ulong\": 5 }"));
 
-  // TODO(james): Make FlatbufferToJson() always print out integer
-  // floating-point numbers identically.
-  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 5.0 }", TestReflection::kNo));
-  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 5.0 }", TestReflection::kNo));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 5 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 50 }"));
+  // Test that we can distinguish between floats that vary by a single bit.
+  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 1.1 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 1.0999999 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 5 }"));
+  // Check that we handle/distinguish between doubles that vary by a single bit.
+  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 1.561154546713 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 1.56115454671299 }"));
 
   EXPECT_TRUE(JsonAndBack("{ \"foo_enum\": \"None\" }"));
   EXPECT_TRUE(JsonAndBack("{ \"foo_enum\": \"UType\" }"));
@@ -116,24 +121,22 @@
                   "\"foo_byte\": 2 } } }"));
   EXPECT_TRUE(JsonAndBack(
       "{ \"foo_struct_scalars\": { \"foo_float\": 1.234, \"foo_double\": "
-      "4.567, \"foo_int32\": -971, \"foo_uint32\": 4294967294, \"foo_int64\": "
-      "-1030, \"foo_uint64\": 18446744073709551614 } }",
+      "4.567, \"foo_int32\": -971, \"foo_uint32\": 4294967294, "
+      "\"foo_int64\": -1030, \"foo_uint64\": 18446744073709551614 } }",
       TestReflection::kNo));
   // Confirm that we parse integers into floating point fields correctly.
   EXPECT_TRUE(JsonAndBack(
       "{ \"foo_struct_scalars\": { \"foo_float\": 1, \"foo_double\": "
       "2, \"foo_int32\": 3, \"foo_uint32\": 4, \"foo_int64\": "
       "5, \"foo_uint64\": 6 } }",
-      "{ \"foo_struct_scalars\": { \"foo_float\": 1.0, \"foo_double\": "
-      "2.0, \"foo_int32\": 3, \"foo_uint32\": 4, \"foo_int64\": "
-      "5, \"foo_uint64\": 6 } }",
       TestReflection::kNo));
   EXPECT_TRUE(JsonAndBack(
       "{ \"vector_foo_struct_scalars\": [ { \"foo_float\": 1.234, "
-      "\"foo_double\": 4.567, \"foo_int32\": -971, \"foo_uint32\": 4294967294, "
-      "\"foo_int64\": -1030, \"foo_uint64\": 18446744073709551614 }, { "
-      "\"foo_float\": 2.0, \"foo_double\": 4.1, \"foo_int32\": 10, "
-      "\"foo_uint32\": 13, \"foo_int64\": 15, \"foo_uint64\": 18 } ] }",
+      "\"foo_double\": 4.567, \"foo_int32\": -971, "
+      "\"foo_uint32\": 4294967294, \"foo_int64\": -1030, \"foo_uint64\": "
+      "18446744073709551614 }, { \"foo_float\": 2, \"foo_double\": "
+      "4.1, \"foo_int32\": 10, \"foo_uint32\": 13, "
+      "\"foo_int64\": 15, \"foo_uint64\": 18 } ] }",
       TestReflection::kNo));
   EXPECT_TRUE(
       JsonAndBack("{ \"foo_struct_enum\": { \"foo_enum\": \"UByte\" } }"));
@@ -209,8 +212,8 @@
 
 // Tests that we can handle decimal points.
 TEST_F(JsonToFlatbufferTest, DecimalPoint) {
-  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 5.1 }"));
-  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 5.1 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_float\": 5.099999 }"));
+  EXPECT_TRUE(JsonAndBack("{ \"foo_double\": 5.099999999999 }"));
 }
 
 // Test what happens if you pass a field name that we don't know.
@@ -283,19 +286,15 @@
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_ulong\": [ 9, 7, 1 ] }"));
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_ulong\": [  ] }"));
 
-  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_float\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_float\": [ 9, 7, 1 ] }"));
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_float\": [  ] }"));
-  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_double\": [ 9, 7, 1 ] }"));
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_double\": [  ] }"));
 
-  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_float\": [ 9, 7, 1 ] }",
-                          "{ \"vector_foo_float\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
-  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_double\": [ 9, 7, 1 ] }",
-                          "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_float\": [ 9.0, 7.0, 1.0 ] }",
+                          "{ \"vector_foo_float\": [ 9, 7, 1 ] }"));
+  EXPECT_TRUE(JsonAndBack("{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
+                          "{ \"vector_foo_double\": [ 9, 7, 1 ] }"));
 
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_string\": [ \"bar\", \"baz\" ] }"));
   EXPECT_TRUE(JsonAndBack("{ \"vector_foo_string\": [  ] }"));
@@ -336,8 +335,7 @@
   /* foo */
   "vector_foo_double": [ 9, 7, 1 ] /* foo */
 } /* foo */)",
-                          "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+                          "{ \"vector_foo_double\": [ 9, 7, 1 ] }"));
 }
 
 // Tests that C++ style comments get stripped.
@@ -346,8 +344,7 @@
   // foo
   "vector_foo_double": [ 9, 7, 1 ] // foo
 } // foo)",
-                          "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+                          "{ \"vector_foo_double\": [ 9, 7, 1 ] }"));
 
   // Test empty comment on its own line doesn't remove the next line.
   EXPECT_TRUE(JsonAndBack(R"({
@@ -355,8 +352,8 @@
   "vector_foo_double": [ 9, 7, 1 ], // foo
   "vector_foo_float": [ 3, 1, 4 ]
 } // foo)",
-                          "{ \"vector_foo_float\": [ 3.0, 1.0, 4.0 ], "
-                          "\"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
+                          "{ \"vector_foo_float\": [ 3, 1, 4 ], "
+                          "\"vector_foo_double\": [ 9, 7, 1 ] }",
                           TestReflection::kNo));
 
   // Test empty comment at end of line doesn't remove the next line.
@@ -365,8 +362,8 @@
   "vector_foo_double": [ 2, 7, 1 ], //
   "vector_foo_float": [ 3, 1, 4 ]
 } // foo)",
-                          "{ \"vector_foo_float\": [ 3.0, 1.0, 4.0 ], "
-                          "\"vector_foo_double\": [ 2.0, 7.0, 1.0 ] }",
+                          "{ \"vector_foo_float\": [ 3, 1, 4 ], "
+                          "\"vector_foo_double\": [ 2, 7, 1 ] }",
                           TestReflection::kNo));
 
   // Test empty comment at end of document doesn't cause error.
@@ -375,8 +372,8 @@
   "vector_foo_double": [ 5, 6, 7 ], // foo
   "vector_foo_float": [ 7, 8, 9 ]
 } //)",
-                          "{ \"vector_foo_float\": [ 7.0, 8.0, 9.0 ], "
-                          "\"vector_foo_double\": [ 5.0, 6.0, 7.0 ] }",
+                          "{ \"vector_foo_float\": [ 7, 8, 9 ], "
+                          "\"vector_foo_double\": [ 5, 6, 7 ] }",
                           TestReflection::kNo));
 }
 
@@ -389,8 +386,8 @@
 }
 // foo
 /* foo */)",
-                          "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
-                          TestReflection::kNo));
+                          "{ \"vector_foo_double\": [ 9, 7, 1 ] }",
+                          TestReflection::kYes));
 }
 
 // Tests that multiple arrays get properly handled.
@@ -398,8 +395,6 @@
   EXPECT_TRUE(
       JsonAndBack("{ \"vector_foo_float\": [ 9, 7, 1 ], \"vector_foo_double\": "
                   "[ 9, 7, 1 ] }",
-                  "{ \"vector_foo_float\": [ 9.0, 7.0, 1.0 ], "
-                  "\"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }",
                   TestReflection::kNo));
 }