Merge pull request #381 from bknecht/precision

Resolves #284
This commit is contained in:
Christopher Dunn 2015-10-15 16:15:15 -05:00
commit 772f634548
2 changed files with 56 additions and 7 deletions

View File

@ -133,17 +133,20 @@ std::string valueToString(UInt value) {
#endif // # if defined(JSON_HAS_INT64) #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 // Allocate a buffer that is more than large enough to store the 16 digits of
// precision requested below. // precision requested below.
char buffer[32]; char buffer[32];
int len = -1; int len = -1;
char formatString[6];
sprintf(formatString, "%%.%dg", precision);
// Print into the buffer. We need not request the alternative representation // Print into the buffer. We need not request the alternative representation
// that always has a decimal point because JSON doesn't distingish the // that always has a decimal point because JSON doesn't distingish the
// concepts of reals and integers. // concepts of reals and integers.
if (isfinite(value)) { if (isfinite(value)) {
len = snprintf(buffer, sizeof(buffer), "%.17g", value); len = snprintf(buffer, sizeof(buffer), formatString, value);
} else { } else {
// IEEE standard states that NaN values will not compare to themselves // IEEE standard states that NaN values will not compare to themselves
if (value != value) { if (value != value) {
@ -160,7 +163,7 @@ std::string valueToString(double value, bool useSpecialFloats) {
return buffer; 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"; } std::string valueToString(bool value) { return value ? "true" : "false"; }
@ -832,7 +835,8 @@ struct BuiltStyledStreamWriter : public StreamWriter
std::string const& colonSymbol, std::string const& colonSymbol,
std::string const& nullSymbol, std::string const& nullSymbol,
std::string const& endingLineFeedSymbol, std::string const& endingLineFeedSymbol,
bool useSpecialFloats); bool useSpecialFloats,
unsigned int precision);
int write(Value const& root, std::ostream* sout) override; int write(Value const& root, std::ostream* sout) override;
private: private:
void writeValue(Value const& value); void writeValue(Value const& value);
@ -860,6 +864,7 @@ private:
bool addChildValues_ : 1; bool addChildValues_ : 1;
bool indented_ : 1; bool indented_ : 1;
bool useSpecialFloats_ : 1; bool useSpecialFloats_ : 1;
unsigned int precision_;
}; };
BuiltStyledStreamWriter::BuiltStyledStreamWriter( BuiltStyledStreamWriter::BuiltStyledStreamWriter(
std::string const& indentation, std::string const& indentation,
@ -867,7 +872,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
std::string const& colonSymbol, std::string const& colonSymbol,
std::string const& nullSymbol, std::string const& nullSymbol,
std::string const& endingLineFeedSymbol, std::string const& endingLineFeedSymbol,
bool useSpecialFloats) bool useSpecialFloats,
unsigned int precision)
: rightMargin_(74) : rightMargin_(74)
, indentation_(indentation) , indentation_(indentation)
, cs_(cs) , cs_(cs)
@ -877,6 +883,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
, addChildValues_(false) , addChildValues_(false)
, indented_(false) , indented_(false)
, useSpecialFloats_(useSpecialFloats) , useSpecialFloats_(useSpecialFloats)
, precision_(precision)
{ {
} }
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
@ -906,7 +913,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
pushValue(valueToString(value.asLargestUInt())); pushValue(valueToString(value.asLargestUInt()));
break; break;
case realValue: case realValue:
pushValue(valueToString(value.asDouble(), useSpecialFloats_)); pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
break; break;
case stringValue: case stringValue:
{ {
@ -1121,6 +1128,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool eyc = settings_["enableYAMLCompatibility"].asBool();
bool dnp = settings_["dropNullPlaceholders"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool();
bool usf = settings_["useSpecialFloats"].asBool(); bool usf = settings_["useSpecialFloats"].asBool();
unsigned int pre = settings_["precision"].asUInt();
CommentStyle::Enum cs = CommentStyle::All; CommentStyle::Enum cs = CommentStyle::All;
if (cs_str == "All") { if (cs_str == "All") {
cs = CommentStyle::All; cs = CommentStyle::All;
@ -1139,10 +1147,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
if (dnp) { if (dnp) {
nullSymbol = ""; nullSymbol = "";
} }
if (pre > 17) pre = 17;
std::string endingLineFeedSymbol = ""; std::string endingLineFeedSymbol = "";
return new BuiltStyledStreamWriter( return new BuiltStyledStreamWriter(
indentation, cs, indentation, cs,
colonSymbol, nullSymbol, endingLineFeedSymbol, usf); colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
} }
static void getValidWriterKeys(std::set<std::string>* valid_keys) static void getValidWriterKeys(std::set<std::string>* valid_keys)
{ {
@ -1152,6 +1161,7 @@ static void getValidWriterKeys(std::set<std::string>* valid_keys)
valid_keys->insert("enableYAMLCompatibility"); valid_keys->insert("enableYAMLCompatibility");
valid_keys->insert("dropNullPlaceholders"); valid_keys->insert("dropNullPlaceholders");
valid_keys->insert("useSpecialFloats"); valid_keys->insert("useSpecialFloats");
valid_keys->insert("precision");
} }
bool StreamWriterBuilder::validate(Json::Value* invalid) const bool StreamWriterBuilder::validate(Json::Value* invalid) const
{ {
@ -1183,6 +1193,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
(*settings)["enableYAMLCompatibility"] = false; (*settings)["enableYAMLCompatibility"] = false;
(*settings)["dropNullPlaceholders"] = false; (*settings)["dropNullPlaceholders"] = false;
(*settings)["useSpecialFloats"] = false; (*settings)["useSpecialFloats"] = false;
(*settings)["precision"] = 17;
//! [StreamWriterBuilderDefaults] //! [StreamWriterBuilderDefaults]
} }

View File

@ -1675,6 +1675,43 @@ JSONTEST_FIXTURE(ValueTest, specialFloats) {
JSONTEST_ASSERT_STRING_EQUAL(expected, result); 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 {}; struct WriterTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) { 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, zeroes);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, precision);
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);