| 16970 | */ |
| 16971 | template<typename FloatType> |
| 16972 | boundaries compute_boundaries(FloatType value) |
| 16973 | { |
| 16974 | JSON_ASSERT(std::isfinite(value)); |
| 16975 | JSON_ASSERT(value > 0); |
| 16976 | |
| 16977 | // Convert the IEEE representation into a diyfp. |
| 16978 | // |
| 16979 | // If v is denormal: |
| 16980 | // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) |
| 16981 | // If v is normalized: |
| 16982 | // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) |
| 16983 | |
| 16984 | static_assert(std::numeric_limits<FloatType>::is_iec559, |
| 16985 | "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); |
| 16986 | |
| 16987 | constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit) |
| 16988 | constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1); |
| 16989 | constexpr int kMinExp = 1 - kBias; |
| 16990 | constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) |
| 16991 | |
| 16992 | using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type; |
| 16993 | |
| 16994 | const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value)); |
| 16995 | const std::uint64_t E = bits >> (kPrecision - 1); |
| 16996 | const std::uint64_t F = bits & (kHiddenBit - 1); |
| 16997 | |
| 16998 | const bool is_denormal = E == 0; |
| 16999 | const diyfp v = is_denormal |
| 17000 | ? diyfp(F, kMinExp) |
| 17001 | : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias); |
| 17002 | |
| 17003 | // Compute the boundaries m- and m+ of the floating-point value |
| 17004 | // v = f * 2^e. |
| 17005 | // |
| 17006 | // Determine v- and v+, the floating-point predecessor and successor if v, |
| 17007 | // respectively. |
| 17008 | // |
| 17009 | // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) |
| 17010 | // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) |
| 17011 | // |
| 17012 | // v+ = v + 2^e |
| 17013 | // |
| 17014 | // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ |
| 17015 | // between m- and m+ round to v, regardless of how the input rounding |
| 17016 | // algorithm breaks ties. |
| 17017 | // |
| 17018 | // ---+-------------+-------------+-------------+-------------+--- (A) |
| 17019 | // v- m- v m+ v+ |
| 17020 | // |
| 17021 | // -----------------+------+------+-------------+-------------+--- (B) |
| 17022 | // v- m- v m+ v+ |
| 17023 | |
| 17024 | const bool lower_boundary_is_closer = F == 0 && E > 1; |
| 17025 | const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); |
| 17026 | const diyfp m_minus = lower_boundary_is_closer |
| 17027 | ? diyfp(4 * v.f - 1, v.e - 2) // (B) |
| 17028 | : diyfp(2 * v.f - 1, v.e - 1); // (A) |
| 17029 | |