Skip to content

Precision #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions src/lib_json/json_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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"; }

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -860,14 +864,16 @@ struct BuiltStyledStreamWriter : public StreamWriter
bool addChildValues_ : 1;
bool indented_ : 1;
bool useSpecialFloats_ : 1;
unsigned int precision_;
};
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
std::string const& indentation,
CommentStyle::Enum cs,
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)
Expand All @@ -877,6 +883,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
, addChildValues_(false)
, indented_(false)
, useSpecialFloats_(useSpecialFloats)
, precision_(precision)
{
}
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
Expand Down Expand Up @@ -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:
{
Expand Down Expand Up @@ -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;
Expand 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<std::string>* valid_keys)
{
Expand All @@ -1152,6 +1161,7 @@ static void getValidWriterKeys(std::set<std::string>* 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
{
Expand Down Expand Up @@ -1183,6 +1193,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
(*settings)["enableYAMLCompatibility"] = false;
(*settings)["dropNullPlaceholders"] = false;
(*settings)["useSpecialFloats"] = false;
(*settings)["precision"] = 17;
//! [StreamWriterBuilderDefaults]
}

Expand Down
38 changes: 38 additions & 0 deletions src/test_lib_json/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down