Merge pull request #915 from abolz/dtoa

Floating-point formatting
This commit is contained in:
Niels Lohmann 2018-01-21 15:02:57 +01:00 committed by GitHub
commit 010e596001
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 2650 additions and 18 deletions

View file

@ -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 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
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.

File diff suppressed because it is too large Load diff

View file

@ -14,6 +14,7 @@
#include <string> // string
#include <type_traits> // is_same
#include "detail/conversions/to_chars.hpp"
#include "detail/macro_scope.hpp"
#include "detail/meta.hpp"
#include "detail/parsing/output_adapters.hpp"
@ -475,14 +476,36 @@ class serializer
void dump_float(number_float_t x)
{
// NaN / inf
if (not std::isfinite(x) or std::isnan(x))
if (not std::isfinite(x))
{
o->write_characters("null", 4);
return;
}
// get number of digits for a text -> float -> text round-trip
static constexpr auto d = std::numeric_limits<number_float_t>::digits10;
// If number_float_t is an IEEE-754 single or double precision number,
// 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
std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);

File diff suppressed because it is too large Load diff

View file

@ -1 +1 @@
[1.7976931348623157e308]
[1.7976931348623157e+308]

View file

@ -1 +1 @@
[1.2345E-30]
[1.2345e-30]

View file

@ -1 +1 @@
[1.2345E+30]
[1.2345e+30]

View file

@ -593,6 +593,64 @@ TEST_CASE("regression tests")
"[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")
{
std::ifstream f("file_not_found.json");
@ -785,7 +843,7 @@ TEST_CASE("regression tests")
{
json j = json::parse("166020696663385964490");
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)")

View file

@ -307,15 +307,15 @@ TEST_CASE("compliance tests from nativejson-benchmark")
"test/data/json_roundtrip/roundtrip21.json",
"test/data/json_roundtrip/roundtrip22.json",
"test/data/json_roundtrip/roundtrip23.json",
//"test/data/json_roundtrip/roundtrip24.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip25.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip26.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip27.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip28.json", // roundtrip error
"test/data/json_roundtrip/roundtrip24.json",
"test/data/json_roundtrip/roundtrip25.json",
"test/data/json_roundtrip/roundtrip26.json",
"test/data/json_roundtrip/roundtrip27.json",
//"test/data/json_roundtrip/roundtrip28.json", // incompatible with roundtrip24
"test/data/json_roundtrip/roundtrip29.json",
//"test/data/json_roundtrip/roundtrip30.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip31.json", // roundtrip error
"test/data/json_roundtrip/roundtrip32.json"
"test/data/json_roundtrip/roundtrip30.json",
"test/data/json_roundtrip/roundtrip31.json"
//"test/data/json_roundtrip/roundtrip32.json" // same as roundtrip31
})
{
CAPTURE(filename);

469
test/src/unit-to_chars.cpp Normal file
View file

@ -0,0 +1,469 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.0.1
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// XXX:
// Only compile these tests if 'float' and 'double' are IEEE-754 single- and
// double-precision numbers, resp.
#include "catch.hpp"
#include "json.hpp"
using nlohmann::detail::dtoa_impl::reinterpret_bits;
static float make_float(uint32_t sign_bit, uint32_t biased_exponent, uint32_t significand)
{
assert(sign_bit == 0 || sign_bit == 1);
assert(biased_exponent <= 0xFF);
assert(significand <= 0x007FFFFF);
uint32_t bits = 0;
bits |= sign_bit << 31;
bits |= biased_exponent << 23;
bits |= significand;
return reinterpret_bits<float>(bits);
}
// ldexp -- convert f * 2^e to IEEE single precision
static float make_float(uint64_t f, int e)
{
constexpr uint64_t kHiddenBit = 0x00800000;
constexpr uint64_t kSignificandMask = 0x007FFFFF;
constexpr int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
constexpr int kExponentBias = 0x7F + kPhysicalSignificandSize;
constexpr int kDenormalExponent = 1 - kExponentBias;
constexpr int kMaxExponent = 0xFF - kExponentBias;
while (f > kHiddenBit + kSignificandMask) {
f >>= 1;
e++;
}
if (e >= kMaxExponent) {
return std::numeric_limits<float>::infinity();
}
if (e < kDenormalExponent) {
return 0.0;
}
while (e > kDenormalExponent && (f & kHiddenBit) == 0) {
f <<= 1;
e--;
}
uint64_t biased_exponent;
if (e == kDenormalExponent && (f & kHiddenBit) == 0)
biased_exponent = 0;
else
biased_exponent = static_cast<uint64_t>(e + kExponentBias);
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
return reinterpret_bits<float>(static_cast<uint32_t>(bits));
}
static double make_double(uint64_t sign_bit, uint64_t biased_exponent, uint64_t significand)
{
assert(sign_bit == 0 || sign_bit == 1);
assert(biased_exponent <= 0x7FF);
assert(significand <= 0x000FFFFFFFFFFFFF);
uint64_t bits = 0;
bits |= sign_bit << 63;
bits |= biased_exponent << 52;
bits |= significand;
return reinterpret_bits<double>(bits);
}
// ldexp -- convert f * 2^e to IEEE double precision
static double make_double(uint64_t f, int e)
{
constexpr uint64_t kHiddenBit = 0x0010000000000000;
constexpr uint64_t kSignificandMask = 0x000FFFFFFFFFFFFF;
constexpr int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
constexpr int kExponentBias = 0x3FF + kPhysicalSignificandSize;
constexpr int kDenormalExponent = 1 - kExponentBias;
constexpr int kMaxExponent = 0x7FF - kExponentBias;
while (f > kHiddenBit + kSignificandMask) {
f >>= 1;
e++;
}
if (e >= kMaxExponent) {
return std::numeric_limits<double>::infinity();
}
if (e < kDenormalExponent) {
return 0.0;
}
while (e > kDenormalExponent && (f & kHiddenBit) == 0) {
f <<= 1;
e--;
}
uint64_t biased_exponent;
if (e == kDenormalExponent && (f & kHiddenBit) == 0)
biased_exponent = 0;
else
biased_exponent = static_cast<uint64_t>(e + kExponentBias);
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
return reinterpret_bits<double>(bits);
}
TEST_CASE("digit gen")
{
SECTION("single precision")
{
auto check_float = [](float number, const std::string& digits, int expected_exponent)
{
CAPTURE(number);
CAPTURE(digits);
CAPTURE(expected_exponent);
char buf[32];
int len = 0;
int exponent = 0;
nlohmann::detail::dtoa_impl::grisu2(buf, len, exponent, number);
CHECK(digits == std::string(buf, buf + len));
CHECK(expected_exponent == exponent);
};
check_float(make_float(0, 0, 0x00000001), "1", -45); // min denormal
check_float(make_float(0, 0, 0x007FFFFF), "11754942", -45); // max denormal
check_float(make_float(0, 1, 0x00000000), "11754944", -45); // min normal
check_float(make_float(0, 1, 0x00000001), "11754945", -45);
check_float(make_float(0, 1, 0x007FFFFF), "23509886", -45);
check_float(make_float(0, 2, 0x00000000), "23509887", -45);
check_float(make_float(0, 2, 0x00000001), "2350989", -44);
check_float(make_float(0, 24, 0x00000000), "98607613", -39); // fail if no special case in normalized boundaries
check_float(make_float(0, 30, 0x00000000), "63108872", -37); // fail if no special case in normalized boundaries
check_float(make_float(0, 31, 0x00000000), "12621775", -36); // fail if no special case in normalized boundaries
check_float(make_float(0, 57, 0x00000000), "84703295", -29); // fail if no special case in normalized boundaries
check_float(make_float(0, 254, 0x007FFFFE), "34028233", 31);
check_float(make_float(0, 254, 0x007FFFFF), "34028235", 31); // max normal
// V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal Conversion", manuscript, May 1991,
// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z (report)
// ftp://ftp.ee.lbl.gov/testbase.tar.Z (program)
// Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP
check_float(make_float(12676506, -102), "25", -25);
check_float(make_float(12676506, -103), "125", -26);
check_float(make_float(15445013, 86), "1195", 30);
check_float(make_float(13734123, -138), "39415", -39);
check_float(make_float(12428269, -130), "913085", -38);
check_float(make_float(15334037, -146), "1719005", -43);
check_float(make_float(11518287, -41), "52379105", -13);
check_float(make_float(12584953, -145), "2821644", -43);
check_float(make_float(15961084, -125), "37524328", -38);
check_float(make_float(14915817, -146), "16721209", -44);
check_float(make_float(10845484, -102), "21388946", -31);
check_float(make_float(16431059, -61), "7125836", -18);
// Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP
check_float(make_float(16093626, 69), "95", 26);
check_float(make_float( 9983778, 25), "335", 12);
check_float(make_float(12745034, 104), "2585", 35);
check_float(make_float(12706553, 72), "60005", 24);
check_float(make_float(11005028, 45), "387205", 15);
check_float(make_float(15059547, 71), "3555835", 22);
check_float(make_float(16015691, -99), "25268305", -30);
check_float(make_float( 8667859, 56), "6245851", 17);
check_float(make_float(14855922, -82), "30721327", -25);
check_float(make_float(14855922, -83), "15360663", -25);
check_float(make_float(10144164, -110), "781478", -32);
check_float(make_float(13248074, 95), "52481028", 28);
}
SECTION("double precision")
{
auto check_double = [](double number, const std::string& digits, int expected_exponent)
{
CAPTURE(number);
CAPTURE(digits);
CAPTURE(expected_exponent);
char buf[32];
int len = 0;
int exponent = 0;
nlohmann::detail::dtoa_impl::grisu2(buf, len, exponent, number);
CHECK(digits == std::string(buf, buf + len));
CHECK(expected_exponent == exponent);
};
check_double(make_double(0, 0, 0x0000000000000001), "5", -324); // min denormal
check_double(make_double(0, 0, 0x000FFFFFFFFFFFFF), "2225073858507201", -323); // max denormal
check_double(make_double(0, 1, 0x0000000000000000), "22250738585072014", -324); // min normal
check_double(make_double(0, 1, 0x0000000000000001), "2225073858507202", -323);
check_double(make_double(0, 1, 0x000FFFFFFFFFFFFF), "44501477170144023", -324);
check_double(make_double(0, 2, 0x0000000000000000), "4450147717014403", -323);
check_double(make_double(0, 2, 0x0000000000000001), "4450147717014404", -323);
check_double(make_double(0, 4, 0x0000000000000000), "17800590868057611", -323); // fail if no special case in normalized boundaries
check_double(make_double(0, 5, 0x0000000000000000), "35601181736115222", -323); // fail if no special case in normalized boundaries
check_double(make_double(0, 6, 0x0000000000000000), "7120236347223045", -322); // fail if no special case in normalized boundaries
check_double(make_double(0, 10, 0x0000000000000000), "11392378155556871", -321); // fail if no special case in normalized boundaries
check_double(make_double(0, 2046, 0x000FFFFFFFFFFFFE), "17976931348623155", 292);
check_double(make_double(0, 2046, 0x000FFFFFFFFFFFFF), "17976931348623157", 292); // max normal
// Test different paths in DigitGen
check_double( 10000, "1", 4);
check_double( 1200000, "12", 5);
check_double(4.9406564584124654e-324, "5", -324); // exit integral loop
check_double(2.2250738585072009e-308, "2225073858507201", -323); // exit fractional loop
check_double( 1.82877982605164e-99, "182877982605164", -113);
check_double( 1.1505466208671903e-09, "11505466208671903", -25);
check_double( 5.5645893133766722e+20, "5564589313376672", 5);
check_double( 53.034830388866226, "53034830388866226", -15);
check_double( 0.0021066531670178605, "21066531670178605", -19);
// V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal Conversion", manuscript, May 1991,
// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z (report)
// ftp://ftp.ee.lbl.gov/testbase.tar.Z (program)
// Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP
check_double(make_double(8511030020275656, -342) /* 9.5e-088 */, "95", -89);
check_double(make_double(5201988407066741, -824) /* 4.65e-233 */, "465", -235);
check_double(make_double(6406892948269899, +237) /* 1.415e+087 */, "1415", 84);
check_double(make_double(8431154198732492, +72) /* 3.9815e+037 */, "39815", 33);
check_double(make_double(6475049196144587, +99) /* 4.10405e+045 */, "410405", 40);
check_double(make_double(8274307542972842, +726) /* 2.920845e+234 */, "2920845", 228);
check_double(make_double(5381065484265332, -456) /* 2.8919465e-122 */, "28919465", -129);
check_double(make_double(6761728585499734, -1057) /* 4.37877185e-303 */, "437877185", -311);
check_double(make_double(7976538478610756, +376) /* 1.227701635e+129 */, "1227701635", 120);
check_double(make_double(5982403858958067, +377) /* 1.8415524525e+129 */, "18415524525", 119);
check_double(make_double(5536995190630837, +93) /* 5.48357443505e+043 */, "548357443505", 32);
check_double(make_double(7225450889282194, +710) /* 3.891901811465e+229 */, "3891901811465", 217);
check_double(make_double(7225450889282194, +709) /* 1.9459509057325e+229 */, "19459509057325", 216);
check_double(make_double(8703372741147379, +117) /* 1.44609583816055e+051 */, "144609583816055", 37);
check_double(make_double(8944262675275217, -1001) /* 4.173677474585315e-286 */, "4173677474585315", -301);
check_double(make_double(7459803696087692, -707) /* 1.1079507728788885e-197 */, "11079507728788885", -213);
check_double(make_double(6080469016670379, -381) /* 1.234550136632744e-099 */, "1234550136632744", -114);
check_double(make_double(8385515147034757, +721) /* 9.2503171196036502e+232 */, "925031711960365", 218);
check_double(make_double(7514216811389786, -828) /* 4.1980471502848898e-234 */, "419804715028489", -248);
check_double(make_double(8397297803260511, -345) /* 1.1716315319786511e-088 */, "11716315319786511", -104);
check_double(make_double(6733459239310543, +202) /* 4.3281007284461249e+076 */, "4328100728446125", 61);
check_double(make_double(8091450587292794, -473) /* 3.3177101181600311e-127 */, "3317710118160031", -142);
// Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP
check_double(make_double(6567258882077402, +952) /* 2.5e+302 */, "25", 301);
check_double(make_double(6712731423444934, +535) /* 7.55e+176 */, "755", 174);
check_double(make_double(6712731423444934, +534) /* 3.775e+176 */, "3775", 173);
check_double(make_double(5298405411573037, -957) /* 4.3495e-273 */, "43495", -277);
check_double(make_double(5137311167659507, -144) /* 2.30365e-028 */, "230365", -33);
check_double(make_double(6722280709661868, +363) /* 1.263005e+125 */, "1263005", 119);
check_double(make_double(5344436398034927, -169) /* 7.1422105e-036 */, "71422105", -43);
check_double(make_double(8369123604277281, -853) /* 1.39345735e-241 */, "139345735", -249);
check_double(make_double(8995822108487663, -780) /* 1.414634485e-219 */, "1414634485", -228);
check_double(make_double(8942832835564782, -383) /* 4.5392779195e-100 */, "45392779195", -110);
check_double(make_double(8942832835564782, -384) /* 2.26963895975e-100 */, "226963895975", -111);
check_double(make_double(8942832835564782, -385) /* 1.134819479875e-100 */, "1134819479875", -112);
check_double(make_double(6965949469487146, -249) /* 7.7003665618895e-060 */, "77003665618895", -73);
check_double(make_double(6965949469487146, -250) /* 3.85018328094475e-060 */, "385018328094475", -74);
check_double(make_double(6965949469487146, -251) /* 1.925091640472375e-060 */, "1925091640472375", -75);
check_double(make_double(7487252720986826, +548) /* 6.8985865317742005e+180 */, "68985865317742005", 164);
check_double(make_double(5592117679628511, +164) /* 1.3076622631878654e+065 */, "13076622631878654", 49);
check_double(make_double(8887055249355788, +665) /* 1.3605202075612124e+216 */, "13605202075612124", 200);
check_double(make_double(6994187472632449, +690) /* 3.5928102174759597e+223 */, "35928102174759597", 207);
check_double(make_double(8797576579012143, +588) /* 8.9125197712484552e+192 */, "8912519771248455", 177);
check_double(make_double(7363326733505337, +272) /* 5.5876975736230114e+097 */, "55876975736230114", 81);
check_double(make_double(8549497411294502, -448) /* 1.1762578307285404e-119 */, "11762578307285404", -135);
// Table 20: Stress Inputs for Converting 56-bit Binary to Decimal, < 1/2 ULP
check_double(make_double(50883641005312716, -172) /* 8.4999999999999993e-036 */, "8499999999999999", -51);
check_double(make_double(38162730753984537, -170) /* 2.5499999999999999e-035 */, "255", -37);
check_double(make_double(50832789069151999, -101) /* 2.0049999999999997e-014 */, "20049999999999997", -30);
check_double(make_double(51822367833714164, -109) /* 7.9844999999999994e-017 */, "7984499999999999", -32);
check_double(make_double(66840152193508133, -172) /* 1.1165499999999999e-035 */, "11165499999999999", -51);
check_double(make_double(55111239245584393, -138) /* 1.581615e-025 */, "1581615", -31);
check_double(make_double(71704866733321482, -112) /* 1.3809855e-017 */, "13809855", -24);
check_double(make_double(67160949328233173, -142) /* 1.2046404499999999e-026 */, "12046404499999999", -42);
check_double(make_double(53237141308040189, -152) /* 9.3251405449999991e-030 */, "9325140544999999", -45);
check_double(make_double(62785329394975786, -112) /* 1.2092014595e-017 */, "12092014595", -27);
check_double(make_double(48367680154689523, -77) /* 3.2007045838499998e-007 */, "320070458385", -18);
check_double(make_double(42552223180606797, -102) /* 8.391946324354999e-015 */, "8391946324354999", -30);
check_double(make_double(63626356173011241, -112) /* 1.2253990460585e-017 */, "12253990460585", -30);
check_double(make_double(43566388595783643, -99) /* 6.8735641489760495e-014 */, "687356414897605", -28);
check_double(make_double(54512669636675272, -159) /* 7.459816430480385e-032 */, "7459816430480385", -47);
check_double(make_double(52306490527514614, -167) /* 2.7960588398142552e-034 */, "2796058839814255", -49);
check_double(make_double(52306490527514614, -168) /* 1.3980294199071276e-034 */, "13980294199071276", -50);
check_double(make_double(41024721590449423, -89) /* 6.6279012373057359e-011 */, "6627901237305736", -26);
check_double(make_double(37664020415894738, -132) /* 6.9177880043968072e-024 */, "6917788004396807", -39);
check_double(make_double(37549883692866294, -93) /* 3.7915693108349708e-012 */, "3791569310834971", -27);
check_double(make_double(69124110374399839, -104) /* 3.4080817676591365e-015 */, "34080817676591365", -31);
check_double(make_double(69124110374399839, -105) /* 1.7040408838295683e-015 */, "17040408838295683", -31);
// Table 21: Stress Inputs for Converting 56-bit Binary to Decimal, > 1/2 ULP
check_double(make_double(49517601571415211, -94) /* 2.4999999999999998e-012 */, "25", -13);
check_double(make_double(49517601571415211, -95) /* 1.2499999999999999e-012 */, "125", -14);
check_double(make_double(54390733528642804, -133) /* 4.9949999999999996e-024 */, "49949999999999996", -40); // shortest: 4995e-27
check_double(make_double(71805402319113924, -157) /* 3.9304999999999998e-031 */, "39304999999999998", -47); // shortest: 39305e-35
check_double(make_double(40435277969631694, -179) /* 5.2770499999999992e-038 */, "5277049999999999", -53);
check_double(make_double(57241991568619049, -165) /* 1.223955e-033 */, "1223955", -39);
check_double(make_double(65224162876242886, +58) /* 1.8799584999999998e+034 */, "18799584999999998", 18);
check_double(make_double(70173376848895368, -138) /* 2.01387715e-025 */, "201387715", -33);
check_double(make_double(37072848117383207, -99) /* 5.8490641049999989e-014 */, "5849064104999999", -29);
check_double(make_double(56845051585389697, -176) /* 5.9349003054999999e-037 */, "59349003055", -47);
check_double(make_double(54791673366936431, -145) /* 1.2284718039499998e-027 */, "12284718039499998", -43);
check_double(make_double(66800318669106231, -169) /* 8.9270767180849991e-035 */, "8927076718084999", -50);
check_double(make_double(66800318669106231, -170) /* 4.4635383590424995e-035 */, "44635383590424995", -51);
check_double(make_double(66574323440112438, -119) /* 1.0016990862549499e-019 */, "10016990862549499", -35);
check_double(make_double(65645179969330963, -173) /* 5.4829412628024647e-036 */, "5482941262802465", -51);
check_double(make_double(61847254334681076, -109) /* 9.5290783281036439e-017 */, "9529078328103644", -32);
check_double(make_double(39990712921393606, -145) /* 8.9662279366405553e-028 */, "8966227936640555", -43);
check_double(make_double(59292318184400283, -149) /* 8.3086234418058538e-029 */, "8308623441805854", -44);
check_double(make_double(69116558615326153, -143) /* 6.1985873566126555e-027 */, "61985873566126555", -43);
check_double(make_double(69116558615326153, -144) /* 3.0992936783063277e-027 */, "30992936783063277", -43);
check_double(make_double(39462549494468513, -152) /* 6.9123512506176015e-030 */, "6912351250617602", -45);
check_double(make_double(39462549494468513, -153) /* 3.4561756253088008e-030 */, "3456175625308801", -45);
}
}
TEST_CASE("formatting")
{
SECTION("single precision")
{
auto check_float = [](float number, const std::string& expected)
{
char buf[32];
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
std::string actual(buf, end);
CHECK(actual == expected);
};
// %.9g
check_float( -1.2345e-22f, "-1.2345e-22" ); // -1.23450004e-22
check_float( -1.2345e-21f, "-1.2345e-21" ); // -1.23450002e-21
check_float( -1.2345e-20f, "-1.2345e-20" ); // -1.23450002e-20
check_float( -1.2345e-19f, "-1.2345e-19" ); // -1.23449999e-19
check_float( -1.2345e-18f, "-1.2345e-18" ); // -1.23449996e-18
check_float( -1.2345e-17f, "-1.2345e-17" ); // -1.23449998e-17
check_float( -1.2345e-16f, "-1.2345e-16" ); // -1.23449996e-16
check_float( -1.2345e-15f, "-1.2345e-15" ); // -1.23450002e-15
check_float( -1.2345e-14f, "-1.2345e-14" ); // -1.23450004e-14
check_float( -1.2345e-13f, "-1.2345e-13" ); // -1.23449997e-13
check_float( -1.2345e-12f, "-1.2345e-12" ); // -1.23450002e-12
check_float( -1.2345e-11f, "-1.2345e-11" ); // -1.2345e-11
check_float( -1.2345e-10f, "-1.2345e-10" ); // -1.2345e-10
check_float( -1.2345e-9f, "-1.2345e-09" ); // -1.23449995e-09
check_float( -1.2345e-8f, "-1.2345e-08" ); // -1.23449997e-08
check_float( -1.2345e-7f, "-1.2345e-07" ); // -1.23449993e-07
check_float( -1.2345e-6f, "-1.2345e-06" ); // -1.23450002e-06
check_float( -1.2345e-5f, "-1.2345e-05" ); // -1.2345e-05
check_float( -1.2345e-4f, "-0.00012345" ); // -0.000123449994
check_float( -1.2345e-3f, "-0.0012345" ); // -0.00123449997
check_float( -1.2345e-2f, "-0.012345" ); // -0.0123450002
check_float( -1.2345e-1f, "-0.12345" ); // -0.123450004
check_float( -0.0f, "-0.0" ); // -0
check_float( 0.0f, "0.0" ); // 0
check_float( 1.2345e+0f, "1.2345" ); // 1.23450005
check_float( 1.2345e+1f, "12.345" ); // 12.3450003
check_float( 1.2345e+2f, "123.45" ); // 123.449997
check_float( 1.2345e+3f, "1234.5" ); // 1234.5
check_float( 1.2345e+4f, "12345.0" ); // 12345
check_float( 1.2345e+5f, "123450.0" ); // 123450
check_float( 1.2345e+6f, "1.2345e+06" ); // 1234500
check_float( 1.2345e+7f, "1.2345e+07" ); // 12345000
check_float( 1.2345e+8f, "1.2345e+08" ); // 123450000
check_float( 1.2345e+9f, "1.2345e+09" ); // 1.23449997e+09
check_float( 1.2345e+10f, "1.2345e+10" ); // 1.23449999e+10
check_float( 1.2345e+11f, "1.2345e+11" ); // 1.23449999e+11
check_float( 1.2345e+12f, "1.2345e+12" ); // 1.23450006e+12
check_float( 1.2345e+13f, "1.2345e+13" ); // 1.23449995e+13
check_float( 1.2345e+14f, "1.2345e+14" ); // 1.23450002e+14
check_float( 1.2345e+15f, "1.2345e+15" ); // 1.23450003e+15
check_float( 1.2345e+16f, "1.2345e+16" ); // 1.23449998e+16
check_float( 1.2345e+17f, "1.2345e+17" ); // 1.23449996e+17
check_float( 1.2345e+18f, "1.2345e+18" ); // 1.23450004e+18
check_float( 1.2345e+19f, "1.2345e+19" ); // 1.23449999e+19
check_float( 1.2345e+20f, "1.2345e+20" ); // 1.23449999e+20
check_float( 1.2345e+21f, "1.2345e+21" ); // 1.23449999e+21
check_float( 1.2345e+22f, "1.2345e+22" ); // 1.23450005e+22
}
SECTION("double precision")
{
auto check_double = [](double number, const std::string& expected)
{
char buf[32];
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
std::string actual(buf, end);
CHECK(actual == expected);
};
// dtoa %.15g %.17g shortest
check_double( -1.2345e-22, "-1.2345e-22" ); // -1.2345e-22 -1.2345000000000001e-22 -1.2345e-22
check_double( -1.2345e-21, "-1.2345e-21" ); // -1.2345e-21 -1.2345000000000001e-21 -1.2345e-21
check_double( -1.2345e-20, "-1.2345e-20" ); // -1.2345e-20 -1.2345e-20 -1.2345e-20
check_double( -1.2345e-19, "-1.2345e-19" ); // -1.2345e-19 -1.2345000000000001e-19 -1.2345e-19
check_double( -1.2345e-18, "-1.2345e-18" ); // -1.2345e-18 -1.2345000000000001e-18 -1.2345e-18
check_double( -1.2345e-17, "-1.2345e-17" ); // -1.2345e-17 -1.2345e-17 -1.2345e-17
check_double( -1.2345e-16, "-1.2345e-16" ); // -1.2345e-16 -1.2344999999999999e-16 -1.2345e-16
check_double( -1.2345e-15, "-1.2345e-15" ); // -1.2345e-15 -1.2345e-15 -1.2345e-15
check_double( -1.2345e-14, "-1.2345e-14" ); // -1.2345e-14 -1.2345e-14 -1.2345e-14
check_double( -1.2345e-13, "-1.2345e-13" ); // -1.2345e-13 -1.2344999999999999e-13 -1.2345e-13
check_double( -1.2345e-12, "-1.2345e-12" ); // -1.2345e-12 -1.2345e-12 -1.2345e-12
check_double( -1.2345e-11, "-1.2345e-11" ); // -1.2345e-11 -1.2345e-11 -1.2345e-11
check_double( -1.2345e-10, "-1.2345e-10" ); // -1.2345e-10 -1.2345e-10 -1.2345e-10
check_double( -1.2345e-9, "-1.2345e-09" ); // -1.2345e-09 -1.2345e-09 -1.2345e-9
check_double( -1.2345e-8, "-1.2345e-08" ); // -1.2345e-08 -1.2345000000000001e-08 -1.2345e-8
check_double( -1.2345e-7, "-1.2345e-07" ); // -1.2345e-07 -1.2345000000000001e-07 -1.2345e-7
check_double( -1.2345e-6, "-1.2345e-06" ); // -1.2345e-06 -1.2345e-06 -1.2345e-6
check_double( -1.2345e-5, "-1.2345e-05" ); // -1.2345e-05 -1.2345e-05 -1.2345e-5
check_double( -1.2345e-4, "-0.00012345" ); // -0.00012345 -0.00012344999999999999 -0.00012345
check_double( -1.2345e-3, "-0.0012345" ); // -0.0012345 -0.0012344999999999999 -0.0012345
check_double( -1.2345e-2, "-0.012345" ); // -0.012345 -0.012345 -0.012345
check_double( -1.2345e-1, "-0.12345" ); // -0.12345 -0.12345 -0.12345
check_double( -0.0, "-0.0" ); // -0 -0 -0
check_double( 0.0, "0.0" ); // 0 0 0
check_double( 1.2345e+0, "1.2345" ); // 1.2345 1.2344999999999999 1.2345
check_double( 1.2345e+1, "12.345" ); // 12.345 12.345000000000001 12.345
check_double( 1.2345e+2, "123.45" ); // 123.45 123.45 123.45
check_double( 1.2345e+3, "1234.5" ); // 1234.5 1234.5 1234.5
check_double( 1.2345e+4, "12345.0" ); // 12345 12345 12345
check_double( 1.2345e+5, "123450.0" ); // 123450 123450 123450
check_double( 1.2345e+6, "1234500.0" ); // 1234500 1234500 1234500
check_double( 1.2345e+7, "12345000.0" ); // 12345000 12345000 12345000
check_double( 1.2345e+8, "123450000.0" ); // 123450000 123450000 123450000
check_double( 1.2345e+9, "1234500000.0" ); // 1234500000 1234500000 1234500000
check_double( 1.2345e+10, "12345000000.0" ); // 12345000000 12345000000 12345000000
check_double( 1.2345e+11, "123450000000.0" ); // 123450000000 123450000000 123450000000
check_double( 1.2345e+12, "1234500000000.0" ); // 1234500000000 1234500000000 1234500000000
check_double( 1.2345e+13, "12345000000000.0" ); // 12345000000000 12345000000000 12345000000000
check_double( 1.2345e+14, "123450000000000.0" ); // 123450000000000 123450000000000 123450000000000
check_double( 1.2345e+15, "1.2345e+15" ); // 1.2345e+15 1234500000000000 1.2345e15
check_double( 1.2345e+16, "1.2345e+16" ); // 1.2345e+16 12345000000000000 1.2345e16
check_double( 1.2345e+17, "1.2345e+17" ); // 1.2345e+17 1.2345e+17 1.2345e17
check_double( 1.2345e+18, "1.2345e+18" ); // 1.2345e+18 1.2345e+18 1.2345e18
check_double( 1.2345e+19, "1.2345e+19" ); // 1.2345e+19 1.2345e+19 1.2345e19
check_double( 1.2345e+20, "1.2345e+20" ); // 1.2345e+20 1.2345e+20 1.2345e20
check_double( 1.2345e+21, "1.2344999999999999e+21" ); // 1.2345e+21 1.2344999999999999e+21 1.2345e21
check_double( 1.2345e+22, "1.2345e+22" ); // 1.2345e+22 1.2345e+22 1.2345e22
}
}