diff --git a/src/json.hpp b/src/json.hpp index 0594b38d7..13a6c49a9 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6114,24 +6114,26 @@ class basic_json case value_t::number_float: { - // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1) - char buf[263]; - int len; - // check if number was parsed from a string if (m_type.bits.parsed) { // check if parsed number had an exponent given if (m_type.bits.has_exp) { + // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1) + char buf[263]; + int len; + // handle capitalization of the exponent if (m_type.bits.exp_cap) { - len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1; + len = snprintf(buf, sizeof(buf), "%.*E", + m_type.bits.precision, m_value.number_float) + 1; } else { - len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1; + len = snprintf(buf, sizeof(buf), "%.*e", + m_type.bits.precision, m_value.number_float) + 1; } // remove '+' sign from the exponent if necessary @@ -6152,40 +6154,40 @@ class basic_json } } } + + o << buf; } else { // no exponent - output as a decimal - snprintf(buf, sizeof(buf), "%.*f", - m_type.bits.precision, m_value.number_float); + std::stringstream ss; + ss.imbue(std::locale("C")); + ss << std::setprecision(m_type.bits.precision) + << std::fixed << m_value.number_float; + o << ss.str(); } } - else if (m_value.number_float == 0) - { - // special case for zero to get "0.0"/"-0.0" - if (std::signbit(m_value.number_float)) - { - o << "-0.0"; - } - else - { - o << "0.0"; - } - return; - } else { - // Otherwise 6, 15 or 16 digits of precision allows - // round-trip IEEE 754 string->float->string, - // string->double->string or string->long double->string; - // to be safe, we read this value from - // std::numeric_limits::digits10 - snprintf(buf, sizeof(buf), "%.*g", - std::numeric_limits::digits10, - m_value.number_float); + if (m_value.number_float == 0) + { + // special case for zero to get "0.0"/"-0.0" + o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); + } + else + { + // Otherwise 6, 15 or 16 digits of precision allows + // round-trip IEEE 754 string->float->string, + // string->double->string or string->long double->string; + // to be safe, we read this value from + // std::numeric_limits::digits10 + std::stringstream ss; + ss.imbue(std::locale("C")); + ss << std::setprecision(std::numeric_limits::digits10) + << m_value.number_float; + o << ss.str(); + } } - - o << buf; return; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f4ddacf71..70079144f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6114,24 +6114,26 @@ class basic_json case value_t::number_float: { - // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1) - char buf[263]; - int len; - // check if number was parsed from a string if (m_type.bits.parsed) { // check if parsed number had an exponent given if (m_type.bits.has_exp) { + // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1) + char buf[263]; + int len; + // handle capitalization of the exponent if (m_type.bits.exp_cap) { - len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1; + len = snprintf(buf, sizeof(buf), "%.*E", + m_type.bits.precision, m_value.number_float) + 1; } else { - len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1; + len = snprintf(buf, sizeof(buf), "%.*e", + m_type.bits.precision, m_value.number_float) + 1; } // remove '+' sign from the exponent if necessary @@ -6152,40 +6154,40 @@ class basic_json } } } + + o << buf; } else { // no exponent - output as a decimal - snprintf(buf, sizeof(buf), "%.*f", - m_type.bits.precision, m_value.number_float); + std::stringstream ss; + ss.imbue(std::locale("C")); // fix locale problems + ss << std::setprecision(m_type.bits.precision) + << std::fixed << m_value.number_float; + o << ss.str(); } } - else if (m_value.number_float == 0) - { - // special case for zero to get "0.0"/"-0.0" - if (std::signbit(m_value.number_float)) - { - o << "-0.0"; - } - else - { - o << "0.0"; - } - return; - } else { - // Otherwise 6, 15 or 16 digits of precision allows - // round-trip IEEE 754 string->float->string, - // string->double->string or string->long double->string; - // to be safe, we read this value from - // std::numeric_limits::digits10 - snprintf(buf, sizeof(buf), "%.*g", - std::numeric_limits::digits10, - m_value.number_float); + if (m_value.number_float == 0) + { + // special case for zero to get "0.0"/"-0.0" + o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); + } + else + { + // Otherwise 6, 15 or 16 digits of precision allows + // round-trip IEEE 754 string->float->string, + // string->double->string or string->long double->string; + // to be safe, we read this value from + // std::numeric_limits::digits10 + std::stringstream ss; + ss.imbue(std::locale("C")); // fix locale problems + ss << std::setprecision(std::numeric_limits::digits10) + << m_value.number_float; + o << ss.str(); + } } - - o << buf; return; } diff --git a/test/unit.cpp b/test/unit.cpp index b440a28bc..85f8b2294 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -12369,5 +12369,32 @@ TEST_CASE("regression tests") j_long_double = 1.23e45L; CHECK(j_long_double.get() == 1.23e45L); } + + SECTION("issue #228 - double values are serialized with commas as decimal points") + { + json j1a = 23.42; + json j1b = json::parse("23.42"); + + json j2a = 2342e-2; + //issue #230 + //json j2b = json::parse("2342e-2"); + + json j3a = 10E3; + json j3b = json::parse("10E3"); + json j3c = json::parse("10e3"); + + std::locale::global(std::locale("de_DE")); + + CHECK(j1a.dump() == "23.42"); + CHECK(j1b.dump() == "23.42"); + + CHECK(j2a.dump() == "23.42"); + //issue #230 + //CHECK(j2b.dump() == "23.42"); + + CHECK(j3a.dump() == "10000"); + CHECK(j3b.dump() == "1E04"); + CHECK(j3c.dump() == "1e04"); + } }