File indexing completed on 2025-04-19 08:19:38
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP
0009 #define BOOST_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP
0010
0011 #include <boost/charconv/detail/fast_float/float_common.hpp>
0012 #include <boost/charconv/detail/fast_float/bigint.hpp>
0013 #include <boost/charconv/detail/fast_float/ascii_number.hpp>
0014 #include <algorithm>
0015 #include <cstdint>
0016 #include <cstring>
0017 #include <iterator>
0018
0019 namespace boost { namespace charconv { namespace detail { namespace fast_float {
0020
0021
0022 constexpr static uint64_t powers_of_ten_uint64[] = {
0023 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
0024 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
0025 100000000000000UL, 1000000000000000UL, 10000000000000000UL, 100000000000000000UL,
0026 1000000000000000000UL, 10000000000000000000UL};
0027
0028
0029
0030
0031
0032 template <typename UC>
0033 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0034 int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
0035 uint64_t mantissa = num.mantissa;
0036 int32_t exponent = int32_t(num.exponent);
0037 while (mantissa >= 10000) {
0038 mantissa /= 10000;
0039 exponent += 4;
0040 }
0041 while (mantissa >= 100) {
0042 mantissa /= 100;
0043 exponent += 2;
0044 }
0045 while (mantissa >= 10) {
0046 mantissa /= 10;
0047 exponent += 1;
0048 }
0049 return exponent;
0050 }
0051
0052
0053 template <typename T>
0054 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0055 adjusted_mantissa to_extended(T value) noexcept {
0056 using equiv_uint = typename binary_format<T>::equiv_uint;
0057 constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
0058 constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
0059 constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
0060
0061 adjusted_mantissa am;
0062 int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
0063 equiv_uint bits;
0064 #if BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST
0065 bits = std::bit_cast<equiv_uint>(value);
0066 #else
0067 ::memcpy(&bits, &value, sizeof(T));
0068 #endif
0069 if ((bits & exponent_mask) == 0) {
0070
0071 am.power2 = 1 - bias;
0072 am.mantissa = bits & mantissa_mask;
0073 } else {
0074
0075 am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
0076 am.power2 -= bias;
0077 am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
0078 }
0079
0080 return am;
0081 }
0082
0083
0084
0085
0086 template <typename T>
0087 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0088 adjusted_mantissa to_extended_halfway(T value) noexcept {
0089 adjusted_mantissa am = to_extended(value);
0090 am.mantissa <<= 1;
0091 am.mantissa += 1;
0092 am.power2 -= 1;
0093 return am;
0094 }
0095
0096
0097 template <typename T, typename callback>
0098 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0099 void round(adjusted_mantissa& am, callback cb) noexcept {
0100 int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
0101 if (-am.power2 >= mantissa_shift) {
0102
0103 int32_t shift = -am.power2 + 1;
0104 cb(am, std::min<int32_t>(shift, 64));
0105
0106 am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::mantissa_explicit_bits())) ? 0 : 1;
0107 return;
0108 }
0109
0110
0111 cb(am, mantissa_shift);
0112
0113
0114 if (am.mantissa >= (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
0115 am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
0116 am.power2++;
0117 }
0118
0119
0120 am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
0121 if (am.power2 >= binary_format<T>::infinite_power()) {
0122 am.power2 = binary_format<T>::infinite_power();
0123 am.mantissa = 0;
0124 }
0125 }
0126
0127 template <typename callback>
0128 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0129 void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept {
0130 const uint64_t mask
0131 = (shift == 64)
0132 ? UINT64_MAX
0133 : (uint64_t(1) << shift) - 1;
0134 const uint64_t halfway
0135 = (shift == 0)
0136 ? 0
0137 : uint64_t(1) << (shift - 1);
0138 uint64_t truncated_bits = am.mantissa & mask;
0139 bool is_above = truncated_bits > halfway;
0140 bool is_halfway = truncated_bits == halfway;
0141
0142
0143 if (shift == 64) {
0144 am.mantissa = 0;
0145 } else {
0146 am.mantissa >>= shift;
0147 }
0148 am.power2 += shift;
0149
0150 bool is_odd = (am.mantissa & 1) == 1;
0151 am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
0152 }
0153
0154 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0155 void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
0156 if (shift == 64) {
0157 am.mantissa = 0;
0158 } else {
0159 am.mantissa >>= shift;
0160 }
0161 am.power2 += shift;
0162 }
0163 template <typename UC>
0164 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0165 void skip_zeros(UC const * & first, UC const * last) noexcept {
0166 uint64_t val;
0167 while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
0168 ::memcpy(&val, first, sizeof(uint64_t));
0169 if (val != int_cmp_zeros<UC>()) {
0170 break;
0171 }
0172 first += int_cmp_len<UC>();
0173 }
0174 while (first != last) {
0175 if (*first != UC('0')) {
0176 break;
0177 }
0178 first++;
0179 }
0180 }
0181
0182
0183
0184 template <typename UC>
0185 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0186 bool is_truncated(UC const * first, UC const * last) noexcept {
0187
0188 uint64_t val;
0189 while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
0190 ::memcpy(&val, first, sizeof(uint64_t));
0191 if (val != int_cmp_zeros<UC>()) {
0192 return true;
0193 }
0194 first += int_cmp_len<UC>();
0195 }
0196 while (first != last) {
0197 if (*first != UC('0')) {
0198 return true;
0199 }
0200 ++first;
0201 }
0202 return false;
0203 }
0204 template <typename UC>
0205 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0206 bool is_truncated(span<const UC> s) noexcept {
0207 return is_truncated(s.ptr, s.ptr + s.len());
0208 }
0209
0210 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0211 void parse_eight_digits(const char16_t*& , limb& , size_t& , size_t& ) noexcept {
0212
0213 }
0214
0215 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0216 void parse_eight_digits(const char32_t*& , limb& , size_t& , size_t& ) noexcept {
0217
0218 }
0219
0220 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0221 void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
0222 value = value * 100000000 + parse_eight_digits_unrolled(p);
0223 p += 8;
0224 counter += 8;
0225 count += 8;
0226 }
0227
0228 template <typename UC>
0229 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0230 void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
0231 value = value * 10 + limb(*p - UC('0'));
0232 p++;
0233 counter++;
0234 count++;
0235 }
0236
0237 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0238 void add_native(bigint& big, limb power, limb value) noexcept {
0239 big.mul(power);
0240 big.add(value);
0241 }
0242
0243 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0244 void round_up_bigint(bigint& big, size_t& count) noexcept {
0245
0246
0247 add_native(big, 10, 1);
0248 count++;
0249 }
0250
0251
0252 template <typename UC>
0253 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0254 void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_digits, size_t& digits) noexcept {
0255
0256
0257
0258 size_t counter = 0;
0259 digits = 0;
0260 limb value = 0;
0261 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0262 constexpr size_t step = 19;
0263 #else
0264 constexpr size_t step = 9;
0265 #endif
0266
0267
0268 UC const * p = num.integer.ptr;
0269 UC const * pend = p + num.integer.len();
0270 skip_zeros(p, pend);
0271
0272 while (p != pend) {
0273 if (std::is_same<UC,char>::value) {
0274 while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
0275 parse_eight_digits(p, value, counter, digits);
0276 }
0277 }
0278 while (counter < step && p != pend && digits < max_digits) {
0279 parse_one_digit(p, value, counter, digits);
0280 }
0281 if (digits == max_digits) {
0282
0283 add_native(result, limb(powers_of_ten_uint64[counter]), value);
0284 bool truncated = is_truncated(p, pend);
0285 if (num.fraction.ptr != nullptr) {
0286 truncated |= is_truncated(num.fraction);
0287 }
0288 if (truncated) {
0289 round_up_bigint(result, digits);
0290 }
0291 return;
0292 } else {
0293 add_native(result, limb(powers_of_ten_uint64[counter]), value);
0294 counter = 0;
0295 value = 0;
0296 }
0297 }
0298
0299
0300 if (num.fraction.ptr != nullptr) {
0301 p = num.fraction.ptr;
0302 pend = p + num.fraction.len();
0303 if (digits == 0) {
0304 skip_zeros(p, pend);
0305 }
0306
0307 while (p != pend) {
0308 if (std::is_same<UC,char>::value) {
0309 while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
0310 parse_eight_digits(p, value, counter, digits);
0311 }
0312 }
0313 while (counter < step && p != pend && digits < max_digits) {
0314 parse_one_digit(p, value, counter, digits);
0315 }
0316 if (digits == max_digits) {
0317
0318 add_native(result, limb(powers_of_ten_uint64[counter]), value);
0319 bool truncated = is_truncated(p, pend);
0320 if (truncated) {
0321 round_up_bigint(result, digits);
0322 }
0323 return;
0324 } else {
0325 add_native(result, limb(powers_of_ten_uint64[counter]), value);
0326 counter = 0;
0327 value = 0;
0328 }
0329 }
0330 }
0331
0332 if (counter != 0) {
0333 add_native(result, limb(powers_of_ten_uint64[counter]), value);
0334 }
0335 }
0336
0337 template <typename T>
0338 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0339 adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
0340 BOOST_CHARCONV_FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
0341 adjusted_mantissa answer;
0342 bool truncated;
0343 answer.mantissa = bigmant.hi64(truncated);
0344 int bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
0345 answer.power2 = bigmant.bit_length() - 64 + bias;
0346
0347 round<T>(answer, [truncated](adjusted_mantissa& a, int32_t shift) {
0348 round_nearest_tie_even(a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
0349 return is_above || (is_halfway && truncated) || (is_odd && is_halfway);
0350 });
0351 });
0352
0353 return answer;
0354 }
0355
0356
0357
0358
0359
0360
0361 template <typename T>
0362 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0363 adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
0364 bigint& real_digits = bigmant;
0365 int32_t real_exp = exponent;
0366
0367
0368 adjusted_mantissa am_b = am;
0369
0370 round<T>(am_b, [](adjusted_mantissa&a, int32_t shift) { round_down(a, shift); });
0371 T b;
0372 to_float(false, am_b, b);
0373 adjusted_mantissa theor = to_extended_halfway(b);
0374 bigint theor_digits(theor.mantissa);
0375 int32_t theor_exp = theor.power2;
0376
0377
0378 int32_t pow2_exp = theor_exp - real_exp;
0379 uint32_t pow5_exp = uint32_t(-real_exp);
0380 if (pow5_exp != 0) {
0381 BOOST_CHARCONV_FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));
0382 }
0383 if (pow2_exp > 0) {
0384 BOOST_CHARCONV_FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp)));
0385 } else if (pow2_exp < 0) {
0386 BOOST_CHARCONV_FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
0387 }
0388
0389
0390 int ord = real_digits.compare(theor_digits);
0391 adjusted_mantissa answer = am;
0392 round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) {
0393 round_nearest_tie_even(a, shift, [ord](bool is_odd, bool, bool) -> bool {
0394 if (ord > 0) {
0395 return true;
0396 } else if (ord < 0) {
0397 return false;
0398 } else {
0399 return is_odd;
0400 }
0401 });
0402 });
0403
0404 return answer;
0405 }
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420 template <typename T, typename UC>
0421 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0422 adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept {
0423
0424 am.power2 -= invalid_am_bias;
0425
0426 int32_t sci_exp = scientific_exponent(num);
0427 size_t max_digits = binary_format<T>::max_digits();
0428 size_t digits = 0;
0429 bigint bigmant;
0430 parse_mantissa(bigmant, num, max_digits, digits);
0431
0432 int32_t exponent = sci_exp + 1 - int32_t(digits);
0433 if (exponent >= 0) {
0434 return positive_digit_comp<T>(bigmant, exponent);
0435 } else {
0436 return negative_digit_comp<T>(bigmant, am, exponent);
0437 }
0438 }
0439
0440 }}}}
0441
0442 #endif