Convert the floats of json_view from the digit layout

The parser records where the integer digits, the fraction digits, and the
exponent of a float token are. For floats and doubles with at most 19
digits, the value is now read from that layout: the digits eight at a time,
without scanning the token, and rounded by the library's conversion core
(detail::decimal_to_float(): Clinger's fast path where both operands are
exact, else the Eisel-Lemire algorithm, which needs no fallback for up to 19
digits). It rounds correctly, so the values are those of parse(); other
tokens and types keep the library's conversion of the whole token.

get<double>(), materialize(), dump(), and comparisons use it. Traversing
canada.json (111,000 floats, every number converted): 0.95 -> 1.29 GB/s.

Tests add tokens around the limits (19 and 20 digits, 2^53, 10^22, and
those of float) to the bit-for-bit comparison with parse().

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-28 23:24:57 +02:00
parent 4f00cac911
commit cbd93ff4bc
6 changed files with 205 additions and 7 deletions

View File

@@ -873,7 +873,15 @@ TEST_CASE("json_view values")
std::mt19937_64 rng(5295); // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
std::vector<std::string> tokens = {"0.1", "-0.0", "1e308", "1.7976931348623157e308", "2.2250738585072011e-308", "4.9e-324", "5e-324",
"0.1000000000000000055511151231257827021181583404541015625", "123456789012345678901234567890",
"9007199254740993", "1.00000000000000011102230246251565404236316680908203125", "7.2057594037927933e16"
"9007199254740993", "1.00000000000000011102230246251565404236316680908203125", "7.2057594037927933e16",
// around the limits of the conversion from the digit layout: 19 and 20
// digits, and those of Clinger's fast path (2^53, 10^22)
"1234567890.123456789", "1234567890.1234567891", "0.0000000000000000001", "123456789012345678.9",
"9007199254740992.0", "9007199254740993.0", "9007199254740994.0", "1.5e22", "1.5e23", "15e-22", "15e-23",
"1e-400", "0.0e0", "-0.0e-5", "12E+3", "12e-0",
// and of float: 2^24 + 1 and 2^24 + 3 (ties), the subnormal and normal limits
"16777217", "16777219", "1.4e-45", "7.006492321624085e-46", "7.006492321624086e-46",
"1.17549435e-38", "0.30000001192092896", "3.4028234e37"
};
for (int i = 0; i < 20000; ++i)
{