File indexing completed on 2025-04-19 08:19:39
0001
0002
0003
0004
0005
0006 #ifndef BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP
0007 #define BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP
0008
0009 #include <boost/charconv/detail/config.hpp>
0010 #include <boost/charconv/detail/significand_tables.hpp>
0011 #include <boost/charconv/detail/emulated128.hpp>
0012 #include <boost/core/bit.hpp>
0013 #include <cstdint>
0014 #include <cfloat>
0015 #include <cstring>
0016 #include <cmath>
0017
0018 namespace boost { namespace charconv { namespace detail {
0019
0020 static constexpr double powers_of_ten[] = {
0021 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
0022 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
0023 };
0024
0025
0026
0027
0028
0029
0030 inline double compute_float64(std::int64_t power, std::uint64_t i, bool negative, bool& success) noexcept
0031 {
0032 static constexpr auto smallest_power = -325;
0033 static constexpr auto largest_power = 308;
0034
0035
0036
0037
0038
0039 #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
0040 if (0 <= power && power <= 22 && i <= UINT64_C(9007199254740991))
0041 #else
0042 if (-22 <= power && power <= 22 && i <= UINT64_C(9007199254740991))
0043 #endif
0044 {
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 auto d = static_cast<double>(i);
0055
0056 if (power < 0)
0057 {
0058 d = d / powers_of_ten[-power];
0059 }
0060 else
0061 {
0062 d = d * powers_of_ten[power];
0063 }
0064
0065 if (negative)
0066 {
0067 d = -d;
0068 }
0069
0070 success = true;
0071 return d;
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 if (i == 0 || power < smallest_power)
0093 {
0094 return negative ? -0.0 : 0.0;
0095 }
0096 else if (power > largest_power)
0097 {
0098 return negative ? -HUGE_VAL : HUGE_VAL;
0099 }
0100
0101 const std::uint64_t factor_significand = significands_table::significand_64[power - smallest_power];
0102 const std::int64_t exponent = (((152170 + 65536) * power) >> 16) + 1024 + 63;
0103 int leading_zeros = boost::core::countl_zero(i);
0104 i <<= static_cast<std::uint64_t>(leading_zeros);
0105
0106 uint128 product = umul128(i, factor_significand);
0107 std::uint64_t low = product.low;
0108 std::uint64_t high = product.high;
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 if (BOOST_UNLIKELY((high & 0x1FF) == 0x1FF) && (low + i < low))
0125 {
0126 const std::uint64_t factor_significand_low = significands_table::significand_128[power - smallest_power];
0127 product = umul128(i, factor_significand_low);
0128
0129 const std::uint64_t product_middle2 = product.high;
0130 const std::uint64_t product_middle1 = low;
0131 std::uint64_t product_high = high;
0132 const std::uint64_t product_middle = product_middle1 + product_middle2;
0133
0134 if (product_middle < product_middle1)
0135 {
0136 product_high++;
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 low = product_middle;
0152 high = product_high;
0153 }
0154
0155
0156
0157 const std::uint64_t upper_bit = high >> 63;
0158 std::uint64_t significand = high >> (upper_bit + 9);
0159 leading_zeros += static_cast<int>(1 ^ upper_bit);
0160
0161
0162 if (BOOST_UNLIKELY((low == 0) && ((high & 0x1FF) == 0) && ((significand & 3) == 1)))
0163 {
0164
0165 success = false;
0166 return 0;
0167 }
0168
0169 significand += significand & 1;
0170 significand >>= 1;
0171
0172
0173 if (significand >= (UINT64_C(1) << 53))
0174 {
0175 significand = (UINT64_C(1) << 52);
0176 leading_zeros--;
0177 }
0178
0179 significand &= ~(UINT64_C(1) << 52);
0180 const auto real_exponent = static_cast<std::uint64_t>(exponent - leading_zeros);
0181
0182
0183 if (BOOST_UNLIKELY((real_exponent < 1) || (real_exponent > 2046)))
0184 {
0185 success = false;
0186 return 0;
0187 }
0188
0189 significand |= real_exponent << 52;
0190 significand |= ((static_cast<std::uint64_t>(negative) << 63));
0191
0192 double d;
0193 std::memcpy(&d, &significand, sizeof(d));
0194
0195 success = true;
0196 return d;
0197 }
0198
0199 }}}
0200
0201 #endif