diff --git a/src/fptostring.cpp b/src/fptostring.cpp index 3026cbd08..d5c1ca26c 100644 --- a/src/fptostring.cpp +++ b/src/fptostring.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -86,7 +88,8 @@ std::string FpToString(T v, int precision = 0) { if (v == 0 || std::isinf(v) || std::isnan(v)) { std::stringstream ss; ss.imbue(std::locale::classic()); - ss << v; + // force the presecence of one decimal digit for 0 + ss << std::fixed << std::setprecision(1) << v; return ss.str(); } @@ -204,6 +207,11 @@ std::string FpToString(T v, int precision = 0) { for (;digits_iter < digits_end; ++digits_iter) { *(output_ptr++) = *digits_iter; } + } else { + // if no digits after decimal point, print .0 + // to make sure it is recognized as a floating point number + *(output_ptr++) = '.'; + *(output_ptr++) = '0'; } } *output_ptr = '\0'; diff --git a/test/fptostring_test.cpp b/test/fptostring_test.cpp index 3f377abf2..553e0e7be 100644 --- a/test/fptostring_test.cpp +++ b/test/fptostring_test.cpp @@ -1,3 +1,7 @@ +#include +#include +#include + #include "yaml-cpp/fptostring.h" #include "gtest/gtest.h" @@ -7,14 +11,23 @@ namespace { /** * Helper function, that converts double to string as std::stringstream would do */ -template +template ::value, + bool>::type = true> static std::string convert_with_stringstream(T v, size_t precision = 0) { std::stringstream ss; if (precision > 0) { ss << std::setprecision(precision); } ss << v; - return ss.str(); + std::string result = ss.str(); + // Check if already in scientific notation or already has a decimal point + // This logic mimics the logic in FpToString + if (std::isfinite(v) && result.find('e') == std::string::npos && + result.find('.') == std::string::npos) { + // Add .0 to whole numbers not in scientific notation + result += ".0"; + } + return result; } // Caution: Test involving 'convert_with_stringstream' are based on std::stringstream @@ -51,13 +64,13 @@ TEST(FpToStringTest, conversion_double) { EXPECT_EQ(convert_with_stringstream(1e9), FpToString(1e9)); // Print by default values below 1e6 without scientific notation - EXPECT_EQ("1", FpToString(1.)); - EXPECT_EQ("1", FpToString(1e0)); - EXPECT_EQ("10", FpToString(1e1)); - EXPECT_EQ("100", FpToString(1e2)); - EXPECT_EQ("1000", FpToString(1e3)); - EXPECT_EQ("10000", FpToString(1e4)); - EXPECT_EQ("100000", FpToString(1e5)); + EXPECT_EQ("1.0", FpToString(1.)); + EXPECT_EQ("1.0", FpToString(1e0)); + EXPECT_EQ("10.0", FpToString(1e1)); + EXPECT_EQ("100.0", FpToString(1e2)); + EXPECT_EQ("1000.0", FpToString(1e3)); + EXPECT_EQ("10000.0", FpToString(1e4)); + EXPECT_EQ("100000.0", FpToString(1e5)); EXPECT_EQ("1e+06", FpToString(1e6)); EXPECT_EQ("1e+07", FpToString(1e7)); EXPECT_EQ("1e+08", FpToString(1e8)); @@ -77,8 +90,8 @@ TEST(FpToStringTest, conversion_double) { EXPECT_EQ(convert_with_stringstream(1e-9), FpToString(1e-9)); // Print by default values above 1e-5 without scientific notation - EXPECT_EQ("1", FpToString(1.)); - EXPECT_EQ("1", FpToString(1e-0)); + EXPECT_EQ("1.0", FpToString(1.)); + EXPECT_EQ("1.0", FpToString(1e-0)); EXPECT_EQ("0.1", FpToString(1e-1)); EXPECT_EQ("0.01", FpToString(1e-2)); EXPECT_EQ("0.001", FpToString(1e-3)); @@ -96,9 +109,9 @@ TEST(FpToStringTest, conversion_double) { EXPECT_EQ(convert_with_stringstream(1234567e-9, 7), FpToString(1234567e-9, 7)); EXPECT_EQ(convert_with_stringstream(1234567e-9, 1), FpToString(1234567e-9, 1)); - // known example that is difficult to round - EXPECT_EQ("1", FpToString(0.9999, 2)); - EXPECT_EQ("-1", FpToString(-0.9999, 2)); + // known example that is difficult to round + EXPECT_EQ("1.0", FpToString(0.9999, 2)); + EXPECT_EQ("-1.0", FpToString(-0.9999, 2)); // some more random tests EXPECT_EQ("1.25", FpToString(1.25)); @@ -110,13 +123,13 @@ TEST(FpToStringTest, conversion_double) { EXPECT_EQ("1e-20", FpToString(0.1e-19)); EXPECT_EQ("1.1e-20", FpToString(0.11e-19)); - EXPECT_EQ("19", FpToString(18.9, 2)); - EXPECT_EQ("20", FpToString(19.9, 2)); + EXPECT_EQ("19.0", FpToString(18.9, 2)); + EXPECT_EQ("20.0", FpToString(19.9, 2)); EXPECT_EQ("2e+01", FpToString(19.9, 1)); EXPECT_EQ("1.2e-05", FpToString(1.234e-5, 2)); EXPECT_EQ("1.3e-05", FpToString(1.299e-5, 2)); - EXPECT_EQ("-1", FpToString(-1.)); + EXPECT_EQ("-1.0", FpToString(-1.)); EXPECT_EQ("-1.25", FpToString(-1.25)); EXPECT_EQ("-34.34", FpToString(-34.34)); EXPECT_EQ("-1e+20", FpToString(-1e+20)); @@ -126,11 +139,25 @@ TEST(FpToStringTest, conversion_double) { EXPECT_EQ("-1e-20", FpToString(-0.1e-19)); EXPECT_EQ("-1.1e-20", FpToString(-0.11e-19)); - EXPECT_EQ("-19", FpToString(-18.9, 2)); - EXPECT_EQ("-20", FpToString(-19.9, 2)); + EXPECT_EQ("-19.0", FpToString(-18.9, 2)); + EXPECT_EQ("-20.0", FpToString(-19.9, 2)); EXPECT_EQ("-2e+01", FpToString(-19.9, 1)); EXPECT_EQ("-1.2e-05", FpToString(-1.234e-5, 2)); EXPECT_EQ("-1.3e-05", FpToString(-1.299e-5, 2)); + + // special values: 0, inf, -inf, NaN + EXPECT_EQ("0.0", FpToString(0.0)); + EXPECT_EQ("inf", FpToString(std::numeric_limits::infinity())); + EXPECT_EQ("-inf", FpToString(-std::numeric_limits::infinity())); + EXPECT_EQ("nan", FpToString(std::numeric_limits::quiet_NaN())); + + // prints the same way as std::stringstream + EXPECT_EQ(convert_with_stringstream(std::numeric_limits::infinity()), + FpToString(std::numeric_limits::infinity())); + EXPECT_EQ(convert_with_stringstream(-std::numeric_limits::infinity()), + FpToString(-std::numeric_limits::infinity())); + EXPECT_EQ(convert_with_stringstream(std::numeric_limits::quiet_NaN()), + FpToString(std::numeric_limits::quiet_NaN())); } TEST(FpToStringTest, conversion_float) { @@ -156,13 +183,13 @@ TEST(FpToStringTest, conversion_float) { EXPECT_EQ(convert_with_stringstream(1e9f), FpToString(1e9f)); // Print by default values below 1e6 without scientific notation - EXPECT_EQ("1", FpToString(1.f)); - EXPECT_EQ("1", FpToString(1e0f)); - EXPECT_EQ("10", FpToString(1e1f)); - EXPECT_EQ("100", FpToString(1e2f)); - EXPECT_EQ("1000", FpToString(1e3f)); - EXPECT_EQ("10000", FpToString(1e4f)); - EXPECT_EQ("100000", FpToString(1e5f)); + EXPECT_EQ("1.0", FpToString(1.f)); + EXPECT_EQ("1.0", FpToString(1e0f)); + EXPECT_EQ("10.0", FpToString(1e1f)); + EXPECT_EQ("100.0", FpToString(1e2f)); + EXPECT_EQ("1000.0", FpToString(1e3f)); + EXPECT_EQ("10000.0", FpToString(1e4f)); + EXPECT_EQ("100000.0", FpToString(1e5f)); EXPECT_EQ("1e+06", FpToString(1e6f)); EXPECT_EQ("1e+07", FpToString(1e7f)); EXPECT_EQ("1e+08", FpToString(1e8f)); @@ -182,8 +209,8 @@ TEST(FpToStringTest, conversion_float) { EXPECT_EQ(convert_with_stringstream(1e-9f), FpToString(1e-9f)); // Print by default values above 1e-5 without scientific notation - EXPECT_EQ("1", FpToString(1.f)); - EXPECT_EQ("1", FpToString(1e-0f)); + EXPECT_EQ("1.0", FpToString(1.f)); + EXPECT_EQ("1.0", FpToString(1e-0f)); EXPECT_EQ("0.1", FpToString(1e-1f)); EXPECT_EQ("0.01", FpToString(1e-2f)); EXPECT_EQ("0.001", FpToString(1e-3f)); @@ -201,9 +228,9 @@ TEST(FpToStringTest, conversion_float) { EXPECT_EQ(convert_with_stringstream(1234567e-9f, 7), FpToString(1234567e-9f, 7)); EXPECT_EQ(convert_with_stringstream(1234567e-9f, 1), FpToString(1234567e-9f, 1)); - // known example that is difficult to round - EXPECT_EQ("1", FpToString(0.9999f, 2)); - EXPECT_EQ("-1", FpToString(-0.9999f, 2)); + // known example that is difficult to round + EXPECT_EQ("1.0", FpToString(0.9999f, 2)); + EXPECT_EQ("-1.0", FpToString(-0.9999f, 2)); // some more random tests EXPECT_EQ("1.25", FpToString(1.25f)); @@ -215,13 +242,13 @@ TEST(FpToStringTest, conversion_float) { EXPECT_EQ("1e-20", FpToString(0.1e-19f)); EXPECT_EQ("1.1e-20", FpToString(0.11e-19f)); - EXPECT_EQ("19", FpToString(18.9f, 2)); - EXPECT_EQ("20", FpToString(19.9f, 2)); + EXPECT_EQ("19.0", FpToString(18.9f, 2)); + EXPECT_EQ("20.0", FpToString(19.9f, 2)); EXPECT_EQ("2e+01", FpToString(19.9f, 1)); EXPECT_EQ("1.2e-05", FpToString(1.234e-5f, 2)); EXPECT_EQ("1.3e-05", FpToString(1.299e-5f, 2)); - EXPECT_EQ("-1", FpToString(-1.f)); + EXPECT_EQ("-1.0", FpToString(-1.f)); EXPECT_EQ("-1.25", FpToString(-1.25f)); EXPECT_EQ("-34.34", FpToString(-34.34f)); EXPECT_EQ("-1e+20", FpToString(-1e+20f)); @@ -231,11 +258,25 @@ TEST(FpToStringTest, conversion_float) { EXPECT_EQ("-1e-20", FpToString(-0.1e-19f)); EXPECT_EQ("-1.1e-20", FpToString(-0.11e-19f)); - EXPECT_EQ("-19", FpToString(-18.9f, 2)); - EXPECT_EQ("-20", FpToString(-19.9f, 2)); + EXPECT_EQ("-19.0", FpToString(-18.9f, 2)); + EXPECT_EQ("-20.0", FpToString(-19.9f, 2)); EXPECT_EQ("-2e+01", FpToString(-19.9f, 1)); EXPECT_EQ("-1.2e-05", FpToString(-1.234e-5f, 2)); EXPECT_EQ("-1.3e-05", FpToString(-1.299e-5f, 2)); + + // special values: 0, inf, -inf, NaN + EXPECT_EQ("0.0", FpToString(0.0f)); + EXPECT_EQ("inf", FpToString(std::numeric_limits::infinity())); + EXPECT_EQ("-inf", FpToString(-std::numeric_limits::infinity())); + EXPECT_EQ("nan", FpToString(std::numeric_limits::quiet_NaN())); + + // prints the same way as std::stringstream + EXPECT_EQ(convert_with_stringstream(std::numeric_limits::infinity()), + FpToString(std::numeric_limits::infinity())); + EXPECT_EQ(convert_with_stringstream(-std::numeric_limits::infinity()), + FpToString(-std::numeric_limits::infinity())); + EXPECT_EQ(convert_with_stringstream(std::numeric_limits::quiet_NaN()), + FpToString(std::numeric_limits::quiet_NaN())); } } // namespace diff --git a/test/integration/emitter_test.cpp b/test/integration/emitter_test.cpp index 4bfc136df..302538d5a 100644 --- a/test/integration/emitter_test.cpp +++ b/test/integration/emitter_test.cpp @@ -121,14 +121,17 @@ TEST_F(EmitterTest, NumberPrecision) { out.SetFloatPrecision(3); out.SetDoublePrecision(2); out << BeginSeq; + out << 1.0f; out << 3.1425926f; + out << 0.0; + out << 1.0; out << 53.5893; out << 2384626.4338; out << 1999926.4338; out << 9999926.4338; out << EndSeq; - ExpectEmit("- 3.14\n- 54\n- 2.4e+06\n- 2e+06\n- 1e+07"); + ExpectEmit("- 1.0\n- 3.14\n- 0.0\n- 1.0\n- 54.0\n- 2.4e+06\n- 2e+06\n- 1e+07"); } TEST_F(EmitterTest, SimpleSeq) { diff --git a/test/node/node_test.cpp b/test/node/node_test.cpp index f889059a7..a34a61b47 100644 --- a/test/node/node_test.cpp +++ b/test/node/node_test.cpp @@ -765,7 +765,7 @@ TEST_F(NodeEmitterTest, SimpleFlowSeqNode) { node.push_back(4000.); node.push_back(1.5474251e+26f); - ExpectOutput("[1.5, 2.25, 3.125, 34.34, 56.56, 12.12, 78.78, 0.0003, 4000, 1.5474251e+26]", node); + ExpectOutput("[1.5, 2.25, 3.125, 34.34, 56.56, 12.12, 78.78, 0.0003, 4000.0, 1.5474251e+26]", node); } TEST_F(NodeEmitterTest, NestFlowSeqNode) {