mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 09:16:50 +08:00
Constexpr from_chars
This commit is contained in:
parent
82ee3b1b5f
commit
e4d4e43b21
@ -17,7 +17,7 @@ namespace fast_float {
|
||||
// low part corresponding to the least significant bits.
|
||||
//
|
||||
template <int bit_precision>
|
||||
fastfloat_really_inline
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||
const int index = 2 * int(q - powers::smallest_power_of_five);
|
||||
// For small values of q, e.g., q in [0,27], the answer is always exact because
|
||||
@ -76,7 +76,7 @@ adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept
|
||||
// w * 10 ** q, without rounding the representation up.
|
||||
// the power2 in the exponent will be adjusted by invalid_am_bias.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
||||
int lz = leading_zeroes(w);
|
||||
w <<= lz;
|
||||
@ -90,7 +90,7 @@ adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
||||
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||
// in such cases.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
adjusted_mantissa answer;
|
||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
||||
|
||||
@ -44,7 +44,8 @@ int32_t scientific_exponent(parsed_number_string& num) noexcept {
|
||||
|
||||
// this converts a native floating-point number to an extended-precision float.
|
||||
template <typename T>
|
||||
fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended(T value) noexcept {
|
||||
using equiv_uint = typename binary_format<T>::equiv_uint;
|
||||
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
|
||||
constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
|
||||
@ -53,7 +54,11 @@ fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept {
|
||||
adjusted_mantissa am;
|
||||
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||
equiv_uint bits;
|
||||
#if FASTFLOAT_HAS_BIT_CAST
|
||||
bits = std::bit_cast<equiv_uint>(value);
|
||||
#else
|
||||
::memcpy(&bits, &value, sizeof(T));
|
||||
#endif
|
||||
if ((bits & exponent_mask) == 0) {
|
||||
// denormal
|
||||
am.power2 = 1 - bias;
|
||||
@ -72,7 +77,8 @@ fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept {
|
||||
// we are given a native float that represents b, so we need to adjust it
|
||||
// halfway between b and b+u.
|
||||
template <typename T>
|
||||
fastfloat_really_inline adjusted_mantissa to_extended_halfway(T value) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended_halfway(T value) noexcept {
|
||||
adjusted_mantissa am = to_extended(value);
|
||||
am.mantissa <<= 1;
|
||||
am.mantissa += 1;
|
||||
@ -148,9 +154,10 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
||||
am.power2 += shift;
|
||||
}
|
||||
|
||||
fastfloat_really_inline void skip_zeros(const char*& first, const char* last) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void skip_zeros(const char*& first, const char* last) noexcept {
|
||||
uint64_t val;
|
||||
while (std::distance(first, last) >= 8) {
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != 0x3030303030303030) {
|
||||
break;
|
||||
@ -167,10 +174,11 @@ fastfloat_really_inline void skip_zeros(const char*& first, const char* last) no
|
||||
|
||||
// determine if any non-zero digits were truncated.
|
||||
// all characters must be valid digits.
|
||||
fastfloat_really_inline bool is_truncated(const char* first, const char* last) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(const char* first, const char* last) noexcept {
|
||||
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||
uint64_t val;
|
||||
while (std::distance(first, last) >= 8) {
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != 0x3030303030303030) {
|
||||
return true;
|
||||
@ -186,11 +194,12 @@ fastfloat_really_inline bool is_truncated(const char* first, const char* last) n
|
||||
return false;
|
||||
}
|
||||
|
||||
fastfloat_really_inline bool is_truncated(byte_span s) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(byte_span s) noexcept {
|
||||
return is_truncated(s.ptr, s.ptr + s.len());
|
||||
}
|
||||
|
||||
fastfloat_really_inline
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||
p += 8;
|
||||
@ -206,13 +215,14 @@ void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count
|
||||
count++;
|
||||
}
|
||||
|
||||
fastfloat_really_inline
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void add_native(bigint& big, limb power, limb value) noexcept {
|
||||
big.mul(power);
|
||||
big.add(value);
|
||||
}
|
||||
|
||||
fastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
// need to round-up the digits, but need to avoid rounding
|
||||
// ....9999 to ...10000, which could cause a false halfway point.
|
||||
add_native(big, 10, 1);
|
||||
@ -220,7 +230,8 @@ fastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcep
|
||||
}
|
||||
|
||||
// parse the significant digits into a big integer
|
||||
inline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept {
|
||||
// try to minimize the number of big integer and scalar multiplication.
|
||||
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
||||
// scalar value (9 or 19 digits) for each step.
|
||||
@ -300,7 +311,8 @@ inline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
|
||||
FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
|
||||
adjusted_mantissa answer;
|
||||
bool truncated;
|
||||
@ -323,7 +335,8 @@ inline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent)
|
||||
// we then need to scale by `2^(f- e)`, and then the two significant digits
|
||||
// are of the same magnitude.
|
||||
template <typename T>
|
||||
inline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
bigint& real_digits = bigmant;
|
||||
int32_t real_exp = exponent;
|
||||
|
||||
@ -383,7 +396,8 @@ inline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa
|
||||
// the actual digits. we then compare the big integer representations
|
||||
// of both, and use that to direct rounding.
|
||||
template <typename T>
|
||||
inline adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept {
|
||||
// remove the invalid exponent bias
|
||||
am.power2 -= invalid_am_bias;
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include "float_common.h"
|
||||
|
||||
namespace fast_float {
|
||||
enum chars_format {
|
||||
scientific = 1<<0,
|
||||
@ -48,6 +50,7 @@ struct parse_options {
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
*/
|
||||
template<typename T>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
@ -55,6 +58,7 @@ from_chars_result from_chars(const char *first, const char *last,
|
||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||
*/
|
||||
template<typename T>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||
T &value, parse_options options) noexcept;
|
||||
|
||||
|
||||
@ -20,8 +20,9 @@ namespace detail {
|
||||
* strings a null-free and fixed.
|
||||
**/
|
||||
template <typename T>
|
||||
from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
|
||||
from_chars_result answer;
|
||||
from_chars_result FASTFLOAT_CONSTEXPR14
|
||||
parse_infnan(const char *first, const char *last, T &value) noexcept {
|
||||
from_chars_result answer{};
|
||||
answer.ptr = first;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
bool minusSign = false;
|
||||
@ -127,12 +128,14 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
return from_chars_advanced(first, last, value, parse_options{fmt});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||
T &value, parse_options options) noexcept {
|
||||
|
||||
@ -169,7 +172,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||
// We could check it first (before the previous branch), but
|
||||
// there might be performance advantages at having the check
|
||||
// be last.
|
||||
if(detail::rounds_to_nearest()) {
|
||||
if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||
// We have that fegetround() == FE_TONEAREST.
|
||||
// Next is Clinger's fast path.
|
||||
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user