mirror of
https://github.com/nlohmann/json.git
synced 2026-09-25 09:20:32 +00:00
Fix for printing long doubles bug in dump_float (#3929)
This commit is contained in:
@@ -836,7 +836,7 @@ class serializer
|
|||||||
static int snprintf_float(char* buf, std::size_t size, int d, long double x)
|
static int snprintf_float(char* buf, std::size_t size, int d, long double x)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
return (std::snprintf)(buf, size, "%.*lg", d, x);
|
return (std::snprintf)(buf, size, "%.*Lg", d, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
||||||
|
|||||||
@@ -19828,7 +19828,7 @@ class serializer
|
|||||||
static int snprintf_float(char* buf, std::size_t size, int d, long double x)
|
static int snprintf_float(char* buf, std::size_t size, int d, long double x)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
return (std::snprintf)(buf, size, "%.*lg", d, x);
|
return (std::snprintf)(buf, size, "%.*Lg", d, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
@@ -295,3 +296,73 @@ TEST_CASE("dump with binary values")
|
|||||||
"]");
|
"]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dump for basic_json with long double number_float_t")
|
||||||
|
{
|
||||||
|
// Custom basic_json instantiation with long double as NumberFloatType.
|
||||||
|
// On platforms where long double is wider than double (e.g. GCC/Clang on
|
||||||
|
// Linux/macOS x86_64), dump() goes through the snprintf path in
|
||||||
|
// serializer::dump_float(x, std::false_type). That branch must use the
|
||||||
|
// "%.*Lg" format specifier; using "%.*g" with a long double argument is
|
||||||
|
// undefined behavior and corrupts the output.
|
||||||
|
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string,
|
||||||
|
bool, std::int64_t, std::uint64_t, long double>;
|
||||||
|
|
||||||
|
SECTION("round-trip dump/parse")
|
||||||
|
{
|
||||||
|
constexpr std::array<long double, 13> values =
|
||||||
|
{{
|
||||||
|
0.0L, -0.0L, 1.0L, -1.0L,
|
||||||
|
0.5L, -0.5L, 1.5L, -2.25L,
|
||||||
|
1.23e45L, 1.23e-45L,
|
||||||
|
(std::numeric_limits<long double>::min)(),
|
||||||
|
std::numeric_limits<long double>::lowest(),
|
||||||
|
(std::numeric_limits<long double>::max)()
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (long double v : values)
|
||||||
|
{
|
||||||
|
const long_double_json j = v;
|
||||||
|
const auto s = j.dump();
|
||||||
|
const auto j2 = long_double_json::parse(s);
|
||||||
|
CHECK(j2.template get<long double>() == v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("exact dump string for simple values")
|
||||||
|
{
|
||||||
|
CHECK(long_double_json(0.5L).dump() == "0.5");
|
||||||
|
CHECK(long_double_json(-0.5L).dump() == "-0.5");
|
||||||
|
CHECK(long_double_json(1.5L).dump() == "1.5");
|
||||||
|
CHECK(long_double_json(-2.25L).dump() == "-2.25");
|
||||||
|
CHECK(long_double_json(0.0L).dump() == "0.0");
|
||||||
|
CHECK(long_double_json(1.0L).dump() == "1.0");
|
||||||
|
CHECK(long_double_json(-1.0L).dump() == "-1.0");
|
||||||
|
CHECK(long_double_json(100.0L).dump() == "100.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("NaN and infinity dump as null")
|
||||||
|
{
|
||||||
|
CHECK(long_double_json(std::numeric_limits<long double>::quiet_NaN()).dump() == "null");
|
||||||
|
CHECK(long_double_json(std::numeric_limits<long double>::infinity()).dump() == "null");
|
||||||
|
CHECK(long_double_json(-std::numeric_limits<long double>::infinity()).dump() == "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("dump output matches double for exactly-representable values")
|
||||||
|
{
|
||||||
|
auto check_same = [](long double v_ld, double v_d)
|
||||||
|
{
|
||||||
|
const long_double_json j_ld = v_ld;
|
||||||
|
const json j_d = v_d;
|
||||||
|
CHECK(j_ld.dump() == j_d.dump());
|
||||||
|
};
|
||||||
|
|
||||||
|
check_same(0.0L, 0.0);
|
||||||
|
check_same(0.5L, 0.5);
|
||||||
|
check_same(-0.5L, -0.5);
|
||||||
|
check_same(1.5L, 1.5);
|
||||||
|
check_same(-2.25L, -2.25);
|
||||||
|
check_same(1.0L, 1.0);
|
||||||
|
check_same(100.0L, 100.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user