mirror of
https://github.com/nlohmann/json.git
synced 2026-10-15 18:57:13 +00:00
Fix AppVeyor failures from the Zmij double writer
MSVC 2015 warns C4554 on the shifts with casts in the fractional part of zmij::to_shortest despite the parentheses; with /WX every target fails to build. Name the shift amounts as constants instead. The shortest-digits test built the candidates with one digit fewer via a stream with std::setprecision(digits.size() - 2); the standard library of MSVC 2017 ignores a precision of 0, so for two-digit values the "shorter" candidates were the value itself. Truncate the digits instead: the value lies within half a unit of the last digit, so the truncated digits and their successor are the closest candidates. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
3 files changed
+15
-19
No files matched your search
@@ -184,7 +184,10 @@ JSON_HEDLEY_ALWAYS_INLINE shortest_decimal to_shortest(std::uint64_t bits) noexc
|
||||
const uint128_parts p10 = pow10(-dec_exp - 1);
|
||||
const uint128_parts p = umul192_hi128(p10.high, p10.low, bin_sig << static_cast<unsigned>(shift));
|
||||
std::uint64_t integral = p.high >> static_cast<unsigned>(extra_shift);
|
||||
const std::uint64_t fractional = (p.high << static_cast<unsigned>(64 - extra_shift)) | (p.low >> static_cast<unsigned>(extra_shift));
|
||||
// (no casts in the shifts: MSVC 2015 warns C4554 on them despite the parentheses)
|
||||
constexpr unsigned fractional_low_shift = static_cast<unsigned>(extra_shift);
|
||||
constexpr unsigned fractional_high_shift = 64u - fractional_low_shift;
|
||||
const std::uint64_t fractional = (p.high << fractional_high_shift) | (p.low >> fractional_low_shift);
|
||||
std::uint64_t digit = 0;
|
||||
bool round_up = false;
|
||||
bool round_down = false;
|
||||
|
||||
Generated
+4
-1
@@ -25874,7 +25874,10 @@ JSON_HEDLEY_ALWAYS_INLINE shortest_decimal to_shortest(std::uint64_t bits) noexc
|
||||
const uint128_parts p10 = pow10(-dec_exp - 1);
|
||||
const uint128_parts p = umul192_hi128(p10.high, p10.low, bin_sig << static_cast<unsigned>(shift));
|
||||
std::uint64_t integral = p.high >> static_cast<unsigned>(extra_shift);
|
||||
const std::uint64_t fractional = (p.high << static_cast<unsigned>(64 - extra_shift)) | (p.low >> static_cast<unsigned>(extra_shift));
|
||||
// (no casts in the shifts: MSVC 2015 warns C4554 on them despite the parentheses)
|
||||
constexpr unsigned fractional_low_shift = static_cast<unsigned>(extra_shift);
|
||||
constexpr unsigned fractional_high_shift = 64u - fractional_low_shift;
|
||||
const std::uint64_t fractional = (p.high << fractional_high_shift) | (p.low >> fractional_low_shift);
|
||||
std::uint64_t digit = 0;
|
||||
bool round_up = false;
|
||||
bool round_down = false;
|
||||
|
||||
@@ -21,11 +21,8 @@ using nlohmann::detail::dtoa_impl::reinterpret_bits;
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -689,20 +686,13 @@ void check_shortest(double v)
|
||||
const std::string& digits = de.first;
|
||||
if (digits.size() > 1)
|
||||
{
|
||||
// the decimals of one digit fewer next to the value
|
||||
// (a stream rather than snprintf("%.*e"), whose output GCC cannot bound)
|
||||
std::ostringstream shorter;
|
||||
shorter.imbue(std::locale::classic());
|
||||
shorter << std::scientific << std::setprecision(static_cast<int>(digits.size()) - 2) << v;
|
||||
const auto near = digits_and_exponent(shorter.str());
|
||||
// as an integer with digits.size() - 1 digits
|
||||
std::string m = near.first;
|
||||
int e = near.second;
|
||||
while (m.size() < digits.size() - 1)
|
||||
{
|
||||
m += '0';
|
||||
--e;
|
||||
}
|
||||
// the decimals of one digit fewer next to the value: v lies within
|
||||
// half a unit of the last digit of text, so the closest ones are the
|
||||
// truncated digits and their successor
|
||||
// (not a stream with std::setprecision(digits.size() - 2): the
|
||||
// standard library of MSVC 2017 ignores a precision of 0)
|
||||
const std::string m = digits.substr(0, digits.size() - 1);
|
||||
const int e = de.second + 1;
|
||||
const std::uint64_t mid = std::stoull(m);
|
||||
for (const std::uint64_t candidate :
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user