diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9fa72c2..14b37bc 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -561,7 +561,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const auto len = static_cast(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -605,7 +605,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, const uint32_t magic = ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; const auto tz = countr_zero_32(magic); // 7, 15, 23, 31, or 32 - am_digits nd = (tz == 32) ? 4 : (tz >> 3); + am_bits_t nd = (tz == 32) ? 4 : (tz >> 3); nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { @@ -620,7 +620,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - am_digits rem = len - nd; + am_bits_t rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 8baf86c..bac994f 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -169,18 +169,18 @@ empty_hi64(bool &truncated) noexcept { fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t uint64_hi64(uint64_t r0, bool &truncated) noexcept { truncated = false; - int shl = leading_zeroes(r0); + auto shl = leading_zeroes(r0); return r0 << shl; } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept { - int shl = leading_zeroes(r0); + auto shl = leading_zeroes(r0); if (shl == 0) { truncated = r1 != 0; return r0; } else { - int shr = 64 - shl; + limb_t shr = 64 - shl; truncated = (r1 << shl) != 0; return (r0 << shl) | (r1 >> shr); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 81b28f2..5c67e7b 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -20,7 +20,7 @@ namespace fast_float { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(am_pow_t q, am_mant_t w) noexcept { - am_pow_t const index = 2 * am_pow_t(q - powers::smallest_power_of_five); + am_pow_t const index = 2 * (q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact // because The line value128 firstproduct = full_multiplication(w, // power_of_five_128[index]); gives the exact answer. @@ -71,7 +71,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(am_pow_t q, am_mant_t w, am_digits lz) noexcept { +compute_error_scaled(am_pow_t q, am_mant_t w, am_bits_t lz) noexcept { auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; @@ -86,7 +86,7 @@ compute_error_scaled(am_pow_t q, am_mant_t w, am_digits lz) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(am_pow_t q, am_mant_t w) noexcept { - am_digits const lz = leading_zeroes(w); + auto const lz = leading_zeroes(w); w <<= lz; value128 product = compute_product_approximation(q, w); @@ -118,7 +118,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. - am_digits const lz = leading_zeroes(w); + auto const lz = leading_zeroes(w); w <<= lz; // The required precision is binary::mantissa_explicit_bits() + 3 because @@ -138,7 +138,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - limb_t const upperbit = static_cast(product.high >> 63); + auto const upperbit = static_cast(product.high >> 63); limb_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; answer.mantissa = product.high >> shift; diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index 6a6f901..c3c5c5c 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -33,7 +33,7 @@ template struct powers_template { binary_format::smallest_power_of_ten(); constexpr static am_pow_t largest_power_of_five = binary_format::largest_power_of_ten(); - constexpr static am_digits number_of_entries = + constexpr static am_pow_t number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1); // Powers of five from 5^-342 all the way to 5^308 rounded toward one. constexpr static am_mant_t power_of_five_128[number_of_entries] = { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index cd5e32e..345631e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,12 +33,31 @@ namespace fast_float { +// 64 bit integer is used because mantissa can be up to 53 bits for double. +// Value of the int mantissa in the API. +typedef int_fast64_t am_sign_mant_t; +// An unsigned int avoids signed overflows (which are bad) +typedef uint_fast64_t am_mant_t; + // The number of digits in the mantissa. typedef uint_fast16_t am_digits; // The number of bits in the limb. typedef uint_fast8_t limb_t; +// Size of bits in the mantissa and path and rounding shifts +typedef int_fast8_t am_bits_t; + +// 16 bit signed integer is used for power to cover all double exponents. +typedef int16_t am_pow_t; +// Power bias is signed for handling a denormal float +// or an invalid mantissa. +// Bias so we can get the real exponent with an invalid adjusted_mantissa. +constexpr static am_pow_t invalid_am_bias = + std::numeric_limits::min() + 1; +constexpr static am_pow_t am_bias_limit = + (std::numeric_limits::max() / 8) - 1; + // Type for enum chars_format. typedef uint_fast8_t chars_format_t; @@ -355,8 +374,11 @@ struct alignas(16) value128 { }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits -leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t +leading_zeroes_generic(uint64_t input_num) noexcept { + assert(input_num > 0); + FASTFLOAT_ASSUME(input_num > 0); + uint_fast32_t last_bit = 0; if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; last_bit |= 32; @@ -380,11 +402,11 @@ leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - static_cast(last_bit); + return 63 - static_cast(last_bit); } /* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); @@ -397,21 +419,20 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return static_cast(63 - leading_zero); + return static_cast(63 - leading_zero); #else - return static_cast(leading_zeroes_generic(input_num)); + return static_cast(leading_zeroes_generic(input_num)); #endif #else - return static_cast(__builtin_clzll(input_num)); + return static_cast(__builtin_clzll(input_num)); #endif } /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t countr_zero_generic_32(uint32_t input_num) { - if (input_num == 0) { - return 32; - } + assert(input_num > 0); + FASTFLOAT_ASSUME(input_num > 0); uint_fast16_t last_bit = 0; if (!(input_num & 0x0000FFFF)) { input_num >>= 16; @@ -432,11 +453,11 @@ countr_zero_generic_32(uint32_t input_num) { if (!(input_num & 0x1)) { last_bit |= 1; } - return static_cast(last_bit); + return static_cast(last_bit); } /* count trailing zeroes for 32-bit integers */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t countr_zero_32(uint32_t input_num) { if (cpp20_and_in_constexpr()) { return countr_zero_generic_32(input_num); @@ -444,11 +465,11 @@ countr_zero_32(uint32_t input_num) { #ifdef FASTFLOAT_VISUAL_STUDIO unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, input_num)) { - return static_cast(trailing_zero); + return static_cast(trailing_zero); } return 32; #else - return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); + return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); #endif } @@ -509,25 +530,6 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { return answer; } -// 64 bit integer is used because mantissa can be up to 53 bits for double. -// Value of the int mantissa in the API. -typedef int_fast64_t am_sign_mant_t; -// An unsigned int avoids signed overflows (which are bad) -typedef uint_fast64_t am_mant_t; - -// Size of bits in the mantissa and path and rounding shifts -typedef int_fast8_t am_bits_t; - -// 16 bit signed integer is used for power to cover all double exponents. -// Power bias is signed for handling a denormal float -// or an invalid mantissa. -typedef int_fast16_t am_pow_t; -// Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static am_pow_t invalid_am_bias = - std::numeric_limits::min() + 1; -constexpr static am_pow_t am_bias_limit = - (std::numeric_limits::max() + 1) / 8; - struct alignas(16) adjusted_mantissa { am_mant_t mantissa; am_pow_t power2; @@ -550,21 +552,21 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - static constexpr limb_t mantissa_explicit_bits(); + static constexpr am_bits_t mantissa_explicit_bits(); static constexpr am_pow_t minimum_exponent(); static constexpr am_pow_t infinite_power(); static constexpr am_bits_t sign_index(); static constexpr am_bits_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_bits_t max_exponent_fast_path(); - static constexpr am_bits_t max_exponent_round_to_even(); - static constexpr am_bits_t min_exponent_round_to_even(); - static constexpr equiv_uint max_mantissa_fast_path(am_pow_t power); + static constexpr am_pow_t max_exponent_round_to_even(); + static constexpr am_pow_t min_exponent_round_to_even(); + static constexpr equiv_uint max_mantissa_fast_path(am_pow_t const power); static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_pow_t largest_power_of_ten(); static constexpr am_pow_t smallest_power_of_ten(); - static constexpr T exact_power_of_ten(am_pow_t power); + static constexpr T exact_power_of_ten(am_pow_t const power); static constexpr am_digits max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); @@ -673,32 +675,32 @@ inline constexpr am_bits_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr limb_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr limb_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 23; } template <> -inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -17; } @@ -807,7 +809,7 @@ binary_format::max_exponent_fast_path() { } template <> -inline constexpr limb_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 10; } @@ -829,13 +831,13 @@ binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 5; } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -22; } @@ -934,7 +936,7 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr limb_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 7; } @@ -956,13 +958,13 @@ binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -24; }