diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 38dd784..0b2d7d5 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -133,17 +133,20 @@ std::string valueToString(UInt value) { #endif // # if defined(JSON_HAS_INT64) -std::string valueToString(double value, bool useSpecialFloats) { +std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) { // Allocate a buffer that is more than large enough to store the 16 digits of // precision requested below. char buffer[32]; int len = -1; + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distingish the // concepts of reals and integers. if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", value); + len = snprintf(buffer, sizeof(buffer), formatString, value); } else { // IEEE standard states that NaN values will not compare to themselves if (value != value) { @@ -160,7 +163,7 @@ std::string valueToString(double value, bool useSpecialFloats) { return buffer; } -std::string valueToString(double value) { return valueToString(value, false); } +std::string valueToString(double value) { return valueToString(value, false, 17); } std::string valueToString(bool value) { return value ? "true" : "false"; } @@ -832,7 +835,8 @@ struct BuiltStyledStreamWriter : public StreamWriter std::string const& colonSymbol, std::string const& nullSymbol, std::string const& endingLineFeedSymbol, - bool useSpecialFloats); + bool useSpecialFloats, + unsigned int precision); int write(Value const& root, std::ostream* sout) override; private: void writeValue(Value const& value); @@ -860,6 +864,7 @@ private: bool addChildValues_ : 1; bool indented_ : 1; bool useSpecialFloats_ : 1; + unsigned int precision_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( std::string const& indentation, @@ -867,7 +872,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( std::string const& colonSymbol, std::string const& nullSymbol, std::string const& endingLineFeedSymbol, - bool useSpecialFloats) + bool useSpecialFloats, + unsigned int precision) : rightMargin_(74) , indentation_(indentation) , cs_(cs) @@ -877,6 +883,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( , addChildValues_(false) , indented_(false) , useSpecialFloats_(useSpecialFloats) + , precision_(precision) { } int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) @@ -906,7 +913,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { pushValue(valueToString(value.asLargestUInt())); break; case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_)); + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); break; case stringValue: { @@ -1121,6 +1128,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool(); bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); CommentStyle::Enum cs = CommentStyle::All; if (cs_str == "All") { cs = CommentStyle::All; @@ -1139,10 +1147,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const if (dnp) { nullSymbol = ""; } + if (pre > 17) pre = 17; std::string endingLineFeedSymbol = ""; return new BuiltStyledStreamWriter( indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol, usf); + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); } static void getValidWriterKeys(std::set* valid_keys) { @@ -1152,6 +1161,7 @@ static void getValidWriterKeys(std::set* valid_keys) valid_keys->insert("enableYAMLCompatibility"); valid_keys->insert("dropNullPlaceholders"); valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); } bool StreamWriterBuilder::validate(Json::Value* invalid) const { @@ -1183,6 +1193,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings) (*settings)["enableYAMLCompatibility"] = false; (*settings)["dropNullPlaceholders"] = false; (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; //! [StreamWriterBuilderDefaults] } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index c1061f4..ad0ad5f 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -1675,6 +1675,43 @@ JSONTEST_FIXTURE(ValueTest, specialFloats) { JSONTEST_ASSERT_STRING_EQUAL(expected, result); } +JSONTEST_FIXTURE(ValueTest, precision) { + Json::StreamWriterBuilder b; + b.settings_["precision"] = 5; + + Json::Value v = 100.0/3; + std::string expected = "33.333"; + std::string result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.25000000; + expected = "0.25"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.2563456; + expected = "0.25635"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 1; + expected = "0.3"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 17; + v = 1234857476305.256345694873740545068; + expected = "1234857476305.2563"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 24; + v = 0.256345694873740545068; + expected = "0.25634569487374054"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); +} + struct WriterTest : JsonTest::TestCase {}; JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) { @@ -2489,6 +2526,7 @@ int main(int argc, const char* argv[]) { JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, precision); JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);