Unverified Commit 010e5960 authored by Niels Lohmann's avatar Niels Lohmann Committed by GitHub

Merge pull request #915 from abolz/dtoa

Floating-point formatting
parents 3d776b05 9b9919d4
...@@ -821,6 +821,10 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I ...@@ -821,6 +821,10 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de> The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
* * *
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](http://florian.loitsch.com/)
## Contact ## Contact
If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases.
......
This diff is collapsed.
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <string> // string #include <string> // string
#include <type_traits> // is_same #include <type_traits> // is_same
#include "detail/conversions/to_chars.hpp"
#include "detail/macro_scope.hpp" #include "detail/macro_scope.hpp"
#include "detail/meta.hpp" #include "detail/meta.hpp"
#include "detail/parsing/output_adapters.hpp" #include "detail/parsing/output_adapters.hpp"
...@@ -475,14 +476,36 @@ class serializer ...@@ -475,14 +476,36 @@ class serializer
void dump_float(number_float_t x) void dump_float(number_float_t x)
{ {
// NaN / inf // NaN / inf
if (not std::isfinite(x) or std::isnan(x)) if (not std::isfinite(x))
{ {
o->write_characters("null", 4); o->write_characters("null", 4);
return; return;
} }
// get number of digits for a text -> float -> text round-trip // If number_float_t is an IEEE-754 single or double precision number,
static constexpr auto d = std::numeric_limits<number_float_t>::digits10; // use the Grisu2 algorithm to produce short numbers which are guaranteed
// to round-trip, using strtof and strtod, resp.
//
// NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double
= (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
(std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
}
void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
{
char* begin = number_buffer.data();
char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
o->write_characters(begin, static_cast<size_t>(end - begin));
}
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
{
// get number of digits for a float -> text -> float round-trip
static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
// the actual conversion // the actual conversion
std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
......
This diff is collapsed.
[1.7976931348623157e308] [1.7976931348623157e+308]
\ No newline at end of file \ No newline at end of file
[1.2345E-30] [1.2345e-30]
\ No newline at end of file \ No newline at end of file
[1.2345E+30] [1.2345e+30]
\ No newline at end of file \ No newline at end of file
...@@ -593,6 +593,64 @@ TEST_CASE("regression tests") ...@@ -593,6 +593,64 @@ TEST_CASE("regression tests")
"[json.exception.out_of_range.406] number overflow parsing '22e2222'"); "[json.exception.out_of_range.406] number overflow parsing '22e2222'");
} }
SECTION("issue #360 - Loss of precision when serializing <double>")
{
auto check_roundtrip = [](double number)
{
CAPTURE(number);
json j = number;
CHECK(j.is_number_float());
std::stringstream ss;
ss << j;
CHECK_NOTHROW(ss >> j);
CHECK(j.is_number_float());
CHECK(j.get<json::number_float_t>() == number);
};
check_roundtrip(100000000000.1236);
check_roundtrip(std::numeric_limits<json::number_float_t>::max());
// Some more numbers which fail to roundtrip when serialized with digits10 significand digits (instead of max_digits10)
check_roundtrip(1.541888611948064e-17);
check_roundtrip(5.418771028591015e-16);
check_roundtrip(9.398685592608595e-15);
check_roundtrip(8.826843952762347e-14);
check_roundtrip(8.143291313475335e-13);
check_roundtrip(4.851328172762508e-12);
check_roundtrip(6.677850998084358e-11);
check_roundtrip(3.995398518174525e-10);
check_roundtrip(1.960452605645124e-9);
check_roundtrip(3.551812586302883e-8);
check_roundtrip(2.947988411689261e-7);
check_roundtrip(8.210166748056192e-6);
check_roundtrip(6.104889704266753e-5);
check_roundtrip(0.0008629954631330876);
check_roundtrip(0.004936993881051611);
check_roundtrip(0.08309725102608073);
check_roundtrip(0.5210494268499783);
check_roundtrip(6.382927930939767);
check_roundtrip(59.94947245358671);
check_roundtrip(361.0838651266122);
check_roundtrip(4678.354596181877);
check_roundtrip(61412.17658956043);
check_roundtrip(725696.0799057782);
check_roundtrip(2811732.583399828);
check_roundtrip(30178351.07533605);
check_roundtrip(689684880.3235844);
check_roundtrip(5714887673.555147);
check_roundtrip(84652038821.18808);
check_roundtrip(156510583431.7721);
check_roundtrip(5938450569021.732);
check_roundtrip(83623297654460.33);
check_roundtrip(701466573254773.6);
check_roundtrip(1369013370304513);
check_roundtrip(96963648023094720);
check_roundtrip(3.478237409280108e+17);
}
SECTION("issue #366 - json::parse on failed stream gets stuck") SECTION("issue #366 - json::parse on failed stream gets stuck")
{ {
std::ifstream f("file_not_found.json"); std::ifstream f("file_not_found.json");
...@@ -785,7 +843,7 @@ TEST_CASE("regression tests") ...@@ -785,7 +843,7 @@ TEST_CASE("regression tests")
{ {
json j = json::parse("166020696663385964490"); json j = json::parse("166020696663385964490");
CHECK(j.is_number_float()); CHECK(j.is_number_float());
CHECK(j.dump() == "1.66020696663386e+20"); CHECK(j.get<json::number_float_t>() == static_cast<json::number_float_t>(166020696663385964490.0));
} }
SECTION("issue #405 - Heap-buffer-overflow (OSS-Fuzz issue 342)") SECTION("issue #405 - Heap-buffer-overflow (OSS-Fuzz issue 342)")
......
...@@ -307,15 +307,15 @@ TEST_CASE("compliance tests from nativejson-benchmark") ...@@ -307,15 +307,15 @@ TEST_CASE("compliance tests from nativejson-benchmark")
"test/data/json_roundtrip/roundtrip21.json", "test/data/json_roundtrip/roundtrip21.json",
"test/data/json_roundtrip/roundtrip22.json", "test/data/json_roundtrip/roundtrip22.json",
"test/data/json_roundtrip/roundtrip23.json", "test/data/json_roundtrip/roundtrip23.json",
//"test/data/json_roundtrip/roundtrip24.json", // roundtrip error "test/data/json_roundtrip/roundtrip24.json",
//"test/data/json_roundtrip/roundtrip25.json", // roundtrip error "test/data/json_roundtrip/roundtrip25.json",
//"test/data/json_roundtrip/roundtrip26.json", // roundtrip error "test/data/json_roundtrip/roundtrip26.json",
//"test/data/json_roundtrip/roundtrip27.json", // roundtrip error "test/data/json_roundtrip/roundtrip27.json",
//"test/data/json_roundtrip/roundtrip28.json", // roundtrip error //"test/data/json_roundtrip/roundtrip28.json", // incompatible with roundtrip24
"test/data/json_roundtrip/roundtrip29.json", "test/data/json_roundtrip/roundtrip29.json",
//"test/data/json_roundtrip/roundtrip30.json", // roundtrip error "test/data/json_roundtrip/roundtrip30.json",
//"test/data/json_roundtrip/roundtrip31.json", // roundtrip error "test/data/json_roundtrip/roundtrip31.json"
"test/data/json_roundtrip/roundtrip32.json" //"test/data/json_roundtrip/roundtrip32.json" // same as roundtrip31
}) })
{ {
CAPTURE(filename); CAPTURE(filename);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment