mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 01:06:48 +08:00
Merge branch 'main' into dlemire/adding_more_cxx20_in_ci
This commit is contained in:
commit
c52769174b
8
.github/workflows/vs17-cxx20.yml
vendored
8
.github/workflows/vs17-cxx20.yml
vendored
@ -18,8 +18,12 @@ jobs:
|
|||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: configure
|
- name: configure
|
||||||
run: |
|
run: >-
|
||||||
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination ..
|
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}}
|
||||||
|
-DCMAKE_CXX_STANDARD=20
|
||||||
|
-DFASTFLOAT_TEST=ON
|
||||||
|
-DFASTFLOAT_CONSTEXPR_TESTS=ON
|
||||||
|
-DCMAKE_INSTALL_PREFIX:PATH=destination
|
||||||
- name: build
|
- name: build
|
||||||
run: |
|
run: |
|
||||||
cmake --build build --verbose --config ${{matrix.cfg}} --parallel
|
cmake --build build --verbose --config ${{matrix.cfg}} --parallel
|
||||||
|
|||||||
@ -27,7 +27,16 @@ fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
|||||||
| (val & 0x00000000000000FF) << 56;
|
| (val & 0x00000000000000FF) << 56;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline uint64_t read_u64(const char *chars) {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
uint64_t read_u64(const char *chars) {
|
||||||
|
if (cpp20_and_in_constexpr()) {
|
||||||
|
uint64_t val = 0;
|
||||||
|
for(int i = 0; i < 8; ++i) {
|
||||||
|
val |= uint64_t(*chars) << (i*8);
|
||||||
|
++chars;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
::memcpy(&val, chars, sizeof(uint64_t));
|
::memcpy(&val, chars, sizeof(uint64_t));
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
||||||
@ -37,7 +46,16 @@ fastfloat_really_inline uint64_t read_u64(const char *chars) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
void write_u64(uint8_t *chars, uint64_t val) {
|
||||||
|
if (cpp20_and_in_constexpr()) {
|
||||||
|
for(int i = 0; i < 8; ++i) {
|
||||||
|
*chars = uint8_t(val);
|
||||||
|
val >>= 8;
|
||||||
|
++chars;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
||||||
// Need to read as-if the number was in little-endian order.
|
// Need to read as-if the number was in little-endian order.
|
||||||
val = byteswap(val);
|
val = byteswap(val);
|
||||||
@ -57,7 +75,8 @@ uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
|||||||
return uint32_t(val);
|
return uint32_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||||
return parse_eight_digits_unrolled(read_u64(chars));
|
return parse_eight_digits_unrolled(read_u64(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +86,8 @@ fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val
|
|||||||
0x8080808080808080));
|
0x8080808080808080));
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
return is_made_of_eight_digits_fast(read_u64(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +107,7 @@ struct parsed_number_string {
|
|||||||
|
|
||||||
// Assuming that you use no more than 19 digits, this will
|
// Assuming that you use no more than 19 digits, this will
|
||||||
// parse an ASCII string.
|
// parse an ASCII string.
|
||||||
fastfloat_really_inline
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
||||||
const chars_format fmt = options.format;
|
const chars_format fmt = options.format;
|
||||||
const char decimal_point = options.decimal_point;
|
const char decimal_point = options.decimal_point;
|
||||||
|
|||||||
@ -514,7 +514,7 @@ struct bigint : pow5_tables<> {
|
|||||||
// move limbs
|
// move limbs
|
||||||
limb* dst = vec.data + n;
|
limb* dst = vec.data + n;
|
||||||
const limb* src = vec.data;
|
const limb* src = vec.data;
|
||||||
::memmove(dst, src, sizeof(limb) * vec.len());
|
std::copy_backward(src, src + vec.len(), dst + vec.len());
|
||||||
// fill in empty limbs
|
// fill in empty limbs
|
||||||
limb* first = vec.data;
|
limb* first = vec.data;
|
||||||
limb* last = first + n;
|
limb* last = first + n;
|
||||||
@ -594,7 +594,12 @@ struct bigint : pow5_tables<> {
|
|||||||
exp -= small_step;
|
exp -= small_step;
|
||||||
}
|
}
|
||||||
if (exp != 0) {
|
if (exp != 0) {
|
||||||
FASTFLOAT_TRY(small_mul(vec, limb(small_power_of_5[exp])));
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||||
|
// This is similar to https://github.com/llvm/llvm-project/issues/47746,
|
||||||
|
// except the workaround described there don't work here
|
||||||
|
FASTFLOAT_TRY(
|
||||||
|
small_mul(vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
40
include/fast_float/constexpr_feature_detect.h
Normal file
40
include/fast_float/constexpr_feature_detect.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
|
#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Testing for https://wg21.link/N3652, adopted in C++14
|
||||||
|
#if __cpp_constexpr >= 201304
|
||||||
|
#define FASTFLOAT_CONSTEXPR14 constexpr
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_CONSTEXPR14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cpp_lib_bit_cast >= 201806L
|
||||||
|
#define FASTFLOAT_HAS_BIT_CAST 1
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_HAS_BIT_CAST 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cpp_lib_is_constant_evaluated >= 201811L
|
||||||
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Testing for relevant C++20 constexpr library features
|
||||||
|
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED \
|
||||||
|
&& FASTFLOAT_HAS_BIT_CAST \
|
||||||
|
&& __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||||
|
#define FASTFLOAT_CONSTEXPR20 constexpr
|
||||||
|
#define FASTFLOAT_IS_CONSTEXPR 1
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_CONSTEXPR20
|
||||||
|
#define FASTFLOAT_IS_CONSTEXPR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
@ -17,7 +17,7 @@ namespace fast_float {
|
|||||||
// low part corresponding to the least significant bits.
|
// low part corresponding to the least significant bits.
|
||||||
//
|
//
|
||||||
template <int bit_precision>
|
template <int bit_precision>
|
||||||
fastfloat_really_inline
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||||
const int index = 2 * int(q - powers::smallest_power_of_five);
|
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
|
// 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.
|
// w * 10 ** q, without rounding the representation up.
|
||||||
// the power2 in the exponent will be adjusted by invalid_am_bias.
|
// the power2 in the exponent will be adjusted by invalid_am_bias.
|
||||||
template <typename binary>
|
template <typename binary>
|
||||||
fastfloat_really_inline
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
||||||
int lz = leading_zeroes(w);
|
int lz = leading_zeroes(w);
|
||||||
w <<= lz;
|
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
|
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||||
// in such cases.
|
// in such cases.
|
||||||
template <typename binary>
|
template <typename binary>
|
||||||
fastfloat_really_inline
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||||
adjusted_mantissa answer;
|
adjusted_mantissa answer;
|
||||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
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.
|
// this converts a native floating-point number to an extended-precision float.
|
||||||
template <typename T>
|
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;
|
using equiv_uint = typename binary_format<T>::equiv_uint;
|
||||||
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
|
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
|
||||||
constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_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;
|
adjusted_mantissa am;
|
||||||
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||||
equiv_uint bits;
|
equiv_uint bits;
|
||||||
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
|
bits = std::bit_cast<equiv_uint>(value);
|
||||||
|
#else
|
||||||
::memcpy(&bits, &value, sizeof(T));
|
::memcpy(&bits, &value, sizeof(T));
|
||||||
|
#endif
|
||||||
if ((bits & exponent_mask) == 0) {
|
if ((bits & exponent_mask) == 0) {
|
||||||
// denormal
|
// denormal
|
||||||
am.power2 = 1 - bias;
|
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
|
// we are given a native float that represents b, so we need to adjust it
|
||||||
// halfway between b and b+u.
|
// halfway between b and b+u.
|
||||||
template <typename T>
|
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);
|
adjusted_mantissa am = to_extended(value);
|
||||||
am.mantissa <<= 1;
|
am.mantissa <<= 1;
|
||||||
am.mantissa += 1;
|
am.mantissa += 1;
|
||||||
@ -148,9 +154,10 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
|||||||
am.power2 += shift;
|
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;
|
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));
|
::memcpy(&val, first, sizeof(uint64_t));
|
||||||
if (val != 0x3030303030303030) {
|
if (val != 0x3030303030303030) {
|
||||||
break;
|
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.
|
// determine if any non-zero digits were truncated.
|
||||||
// all characters must be valid digits.
|
// 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.
|
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||||
uint64_t val;
|
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));
|
::memcpy(&val, first, sizeof(uint64_t));
|
||||||
if (val != 0x3030303030303030) {
|
if (val != 0x3030303030303030) {
|
||||||
return true;
|
return true;
|
||||||
@ -186,11 +194,12 @@ fastfloat_really_inline bool is_truncated(const char* first, const char* last) n
|
|||||||
return false;
|
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());
|
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 {
|
void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||||
p += 8;
|
p += 8;
|
||||||
@ -206,13 +215,14 @@ void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
void add_native(bigint& big, limb power, limb value) noexcept {
|
void add_native(bigint& big, limb power, limb value) noexcept {
|
||||||
big.mul(power);
|
big.mul(power);
|
||||||
big.add(value);
|
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
|
// need to round-up the digits, but need to avoid rounding
|
||||||
// ....9999 to ...10000, which could cause a false halfway point.
|
// ....9999 to ...10000, which could cause a false halfway point.
|
||||||
add_native(big, 10, 1);
|
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
|
// 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.
|
// 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
|
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
||||||
// scalar value (9 or 19 digits) for each step.
|
// 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>
|
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)));
|
FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
|
||||||
adjusted_mantissa answer;
|
adjusted_mantissa answer;
|
||||||
bool truncated;
|
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
|
// we then need to scale by `2^(f- e)`, and then the two significant digits
|
||||||
// are of the same magnitude.
|
// are of the same magnitude.
|
||||||
template <typename T>
|
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;
|
bigint& real_digits = bigmant;
|
||||||
int32_t real_exp = exponent;
|
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
|
// the actual digits. we then compare the big integer representations
|
||||||
// of both, and use that to direct rounding.
|
// of both, and use that to direct rounding.
|
||||||
template <typename T>
|
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
|
// remove the invalid exponent bias
|
||||||
am.power2 -= invalid_am_bias;
|
am.power2 -= invalid_am_bias;
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
#include "constexpr_feature_detect.h"
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
enum chars_format {
|
enum chars_format {
|
||||||
scientific = 1<<0,
|
scientific = 1<<0,
|
||||||
@ -48,6 +50,7 @@ struct parse_options {
|
|||||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
from_chars_result from_chars(const char *first, const char *last,
|
||||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
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.
|
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||||
T &value, parse_options options) noexcept;
|
T &value, parse_options options) noexcept;
|
||||||
|
|
||||||
|
|||||||
@ -7,23 +7,8 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#ifdef __has_include
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
#if __has_include(<version>)
|
|
||||||
#include <version>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cpp_lib_bit_cast >= 201806L
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 1
|
|
||||||
#else
|
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cpp_lib_is_constant_evaluated >= 201811L
|
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
|
||||||
#else
|
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
||||||
@ -110,22 +95,6 @@
|
|||||||
// rust style `try!()` macro, or `?` operator
|
// rust style `try!()` macro, or `?` operator
|
||||||
#define FASTFLOAT_TRY(x) { if (!(x)) return false; }
|
#define FASTFLOAT_TRY(x) { if (!(x)) return false; }
|
||||||
|
|
||||||
// Testing for https://wg21.link/N3652, adopted in C++14
|
|
||||||
#if __cpp_constexpr >= 201304
|
|
||||||
#define FASTFLOAT_CONSTEXPR14 constexpr
|
|
||||||
#else
|
|
||||||
#define FASTFLOAT_CONSTEXPR14
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Testing for relevant C++20 constexpr library features
|
|
||||||
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED \
|
|
||||||
&& FASTFLOAT_HAS_BIT_CAST \
|
|
||||||
&& __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
|
||||||
#define FASTFLOAT_CONSTEXPR20 constexpr
|
|
||||||
#else
|
|
||||||
#define FASTFLOAT_CONSTEXPR20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
|
|
||||||
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
||||||
|
|||||||
@ -20,8 +20,9 @@ namespace detail {
|
|||||||
* strings a null-free and fixed.
|
* strings a null-free and fixed.
|
||||||
**/
|
**/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
|
from_chars_result FASTFLOAT_CONSTEXPR14
|
||||||
from_chars_result answer;
|
parse_infnan(const char *first, const char *last, T &value) noexcept {
|
||||||
|
from_chars_result answer{};
|
||||||
answer.ptr = first;
|
answer.ptr = first;
|
||||||
answer.ec = std::errc(); // be optimistic
|
answer.ec = std::errc(); // be optimistic
|
||||||
bool minusSign = false;
|
bool minusSign = false;
|
||||||
@ -132,12 +133,14 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
from_chars_result from_chars(const char *first, const char *last,
|
||||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||||
return from_chars_advanced(first, last, value, parse_options{fmt});
|
return from_chars_advanced(first, last, value, parse_options{fmt});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||||
T &value, parse_options options) noexcept {
|
T &value, parse_options options) noexcept {
|
||||||
|
|
||||||
@ -174,7 +177,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
// We could check it first (before the previous branch), but
|
// We could check it first (before the previous branch), but
|
||||||
// there might be performance advantages at having the check
|
// there might be performance advantages at having the check
|
||||||
// be last.
|
// be last.
|
||||||
if(detail::rounds_to_nearest()) {
|
if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||||
// We have that fegetround() == FE_TONEAREST.
|
// We have that fegetround() == FE_TONEAREST.
|
||||||
// Next is Clinger's fast path.
|
// Next is Clinger's fast path.
|
||||||
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||||
@ -191,7 +194,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||||
if(pns.mantissa == 0) {
|
if(pns.mantissa == 0) {
|
||||||
value = 0;
|
value = pns.negative ? -0. : 0.;
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -31,7 +31,7 @@ for filename in ['LICENSE-MIT', 'LICENSE-APACHE']:
|
|||||||
processed_files[filename] = text
|
processed_files[filename] = text
|
||||||
|
|
||||||
# code
|
# code
|
||||||
for filename in [ 'fast_float.h', 'float_common.h', 'ascii_number.h',
|
for filename in [ 'constexpr_feature_detect.h', 'fast_float.h', 'float_common.h', 'ascii_number.h',
|
||||||
'fast_table.h', 'decimal_to_binary.h', 'bigint.h',
|
'fast_table.h', 'decimal_to_binary.h', 'bigint.h',
|
||||||
'ascii_number.h', 'digit_comparison.h', 'parse_number.h']:
|
'ascii_number.h', 'digit_comparison.h', 'parse_number.h']:
|
||||||
with open('include/fast_float/' + filename, encoding='utf8') as f:
|
with open('include/fast_float/' + filename, encoding='utf8') as f:
|
||||||
@ -75,6 +75,7 @@ def license_content(license_arg):
|
|||||||
text = ''.join([
|
text = ''.join([
|
||||||
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
||||||
*license_content(args.license),
|
*license_content(args.license),
|
||||||
|
processed_files['constexpr_feature_detect.h'],
|
||||||
processed_files['fast_float.h'], processed_files['float_common.h'],
|
processed_files['fast_float.h'], processed_files['float_common.h'],
|
||||||
processed_files['ascii_number.h'], processed_files['fast_table.h'],
|
processed_files['ascii_number.h'], processed_files['fast_table.h'],
|
||||||
processed_files['decimal_to_binary.h'], processed_files['bigint.h'],
|
processed_files['decimal_to_binary.h'], processed_files['bigint.h'],
|
||||||
|
|||||||
@ -60,7 +60,13 @@ fast_float_add_cpp_test(rcppfastfloat_test)
|
|||||||
fast_float_add_cpp_test(example_test)
|
fast_float_add_cpp_test(example_test)
|
||||||
fast_float_add_cpp_test(example_comma_test)
|
fast_float_add_cpp_test(example_comma_test)
|
||||||
fast_float_add_cpp_test(basictest)
|
fast_float_add_cpp_test(basictest)
|
||||||
|
option(FASTFLOAT_CONSTEXPR_TESTS "Constexpr tests" OFF)
|
||||||
|
if (FASTFLOAT_CONSTEXPR_TESTS)
|
||||||
|
target_compile_features(basictest PRIVATE cxx_std_20)
|
||||||
|
target_compile_definitions(basictest PRIVATE FASTFLOAT_CONSTEXPR_TESTS)
|
||||||
|
else()
|
||||||
target_compile_features(basictest PRIVATE cxx_std_17)
|
target_compile_features(basictest PRIVATE cxx_std_17)
|
||||||
|
endif()
|
||||||
|
|
||||||
fast_float_add_cpp_test(long_test)
|
fast_float_add_cpp_test(long_test)
|
||||||
fast_float_add_cpp_test(powersoffive_hardround)
|
fast_float_add_cpp_test(powersoffive_hardround)
|
||||||
|
|||||||
@ -10,8 +10,13 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
#include <type_traits>
|
||||||
#include <cfenv>
|
#include <cfenv>
|
||||||
|
|
||||||
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
|
#include <bit>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SUPPLEMENTAL_TEST_DATA_DIR
|
#ifndef SUPPLEMENTAL_TEST_DATA_DIR
|
||||||
#define SUPPLEMENTAL_TEST_DATA_DIR "data/"
|
#define SUPPLEMENTAL_TEST_DATA_DIR "data/"
|
||||||
#endif
|
#endif
|
||||||
@ -184,6 +189,53 @@ TEST_CASE("parse_zero") {
|
|||||||
CHECK(float64_parsed == 0);
|
CHECK(float64_parsed == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parse_negative_zero") {
|
||||||
|
//
|
||||||
|
// If this function fails, we may be left in a non-standard rounding state.
|
||||||
|
//
|
||||||
|
const char * negative_zero = "-0";
|
||||||
|
uint64_t float64_parsed;
|
||||||
|
double f = -0.;
|
||||||
|
::memcpy(&float64_parsed, &f, sizeof(f));
|
||||||
|
CHECK(float64_parsed == 0x8000'0000'0000'0000);
|
||||||
|
|
||||||
|
fesetround(FE_UPWARD);
|
||||||
|
auto r1 = fast_float::from_chars(negative_zero, negative_zero + 2, f);
|
||||||
|
CHECK(r1.ec == std::errc());
|
||||||
|
std::cout << "FE_UPWARD parsed negative zero as " << iHexAndDec(f) << std::endl;
|
||||||
|
CHECK(f == 0);
|
||||||
|
::memcpy(&float64_parsed, &f, sizeof(f));
|
||||||
|
std::cout << "double as uint64_t is " << float64_parsed << std::endl;
|
||||||
|
CHECK(float64_parsed == 0x8000'0000'0000'0000);
|
||||||
|
|
||||||
|
fesetround(FE_TOWARDZERO);
|
||||||
|
auto r2 = fast_float::from_chars(negative_zero, negative_zero + 2, f);
|
||||||
|
CHECK(r2.ec == std::errc());
|
||||||
|
std::cout << "FE_TOWARDZERO parsed negative zero as " << iHexAndDec(f) << std::endl;
|
||||||
|
CHECK(f == 0);
|
||||||
|
::memcpy(&float64_parsed, &f, sizeof(f));
|
||||||
|
std::cout << "double as uint64_t is " << float64_parsed << std::endl;
|
||||||
|
CHECK(float64_parsed == 0x8000'0000'0000'0000);
|
||||||
|
|
||||||
|
fesetround(FE_DOWNWARD);
|
||||||
|
auto r3 = fast_float::from_chars(negative_zero, negative_zero + 2, f);
|
||||||
|
CHECK(r3.ec == std::errc());
|
||||||
|
std::cout << "FE_DOWNWARD parsed negative zero as " << iHexAndDec(f) << std::endl;
|
||||||
|
CHECK(f == 0);
|
||||||
|
::memcpy(&float64_parsed, &f, sizeof(f));
|
||||||
|
std::cout << "double as uint64_t is " << float64_parsed << std::endl;
|
||||||
|
CHECK(float64_parsed == 0x8000'0000'0000'0000);
|
||||||
|
|
||||||
|
fesetround(FE_TONEAREST);
|
||||||
|
auto r4 = fast_float::from_chars(negative_zero, negative_zero + 2, f);
|
||||||
|
CHECK(r4.ec == std::errc());
|
||||||
|
std::cout << "FE_TONEAREST parsed negative zero as " << iHexAndDec(f) << std::endl;
|
||||||
|
CHECK(f == 0);
|
||||||
|
::memcpy(&float64_parsed, &f, sizeof(f));
|
||||||
|
std::cout << "double as uint64_t is " << float64_parsed << std::endl;
|
||||||
|
CHECK(float64_parsed == 0x8000'0000'0000'0000);
|
||||||
|
}
|
||||||
|
|
||||||
// C++ 17 because it is otherwise annoying to browse all files in a directory.
|
// C++ 17 because it is otherwise annoying to browse all files in a directory.
|
||||||
// We also only run these tests on little endian systems.
|
// We also only run these tests on little endian systems.
|
||||||
#if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && !defined(FASTFLOAT_ODDPLATFORM)
|
#if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && !defined(FASTFLOAT_ODDPLATFORM)
|
||||||
@ -572,53 +624,147 @@ std::string append_zeros(std::string str, size_t number_of_zeros) {
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
namespace {
|
||||||
void check_basic_test_result(const std::string& str, fast_float::from_chars_result result,
|
|
||||||
|
enum class Diag { runtime, comptime };
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
template <Diag diag, class T>
|
||||||
|
constexpr void check_basic_test_result(std::string_view str,
|
||||||
|
fast_float::from_chars_result result,
|
||||||
T actual, T expected) {
|
T actual, T expected) {
|
||||||
INFO("str=" << str << "\n"
|
if constexpr (diag == Diag::runtime) {
|
||||||
|
INFO(
|
||||||
|
"str=" << str << "\n"
|
||||||
<< " expected=" << fHexAndDec(expected) << "\n"
|
<< " expected=" << fHexAndDec(expected) << "\n"
|
||||||
<< " ..actual=" << fHexAndDec(actual) << "\n"
|
<< " ..actual=" << fHexAndDec(actual) << "\n"
|
||||||
<< " expected mantissa=" << iHexAndDec(get_mantissa(expected)) << "\n"
|
<< " expected mantissa=" << iHexAndDec(get_mantissa(expected))
|
||||||
|
<< "\n"
|
||||||
<< " ..actual mantissa=" << iHexAndDec(get_mantissa(actual)));
|
<< " ..actual mantissa=" << iHexAndDec(get_mantissa(actual)));
|
||||||
CHECK_EQ(result.ec, std::errc());
|
|
||||||
CHECK_EQ(result.ptr, str.data() + str.size());
|
|
||||||
CHECK_EQ(copysign(1, actual), copysign(1, expected));
|
|
||||||
CHECK_EQ(std::isnan(actual), std::isnan(expected));
|
|
||||||
CHECK_EQ(actual, expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
struct ComptimeDiag {
|
||||||
void basic_test(std::string str, T expected) {
|
// Purposely not constexpr
|
||||||
|
static void error_not_equal() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FASTFLOAT_CHECK_EQ(...) \
|
||||||
|
if constexpr (diag == Diag::runtime) { \
|
||||||
|
CHECK_EQ(__VA_ARGS__); \
|
||||||
|
} else { \
|
||||||
|
if ([](const auto &lhs, const auto &rhs) { \
|
||||||
|
return lhs != rhs; \
|
||||||
|
}(__VA_ARGS__)) { \
|
||||||
|
ComptimeDiag::error_not_equal(); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
auto copysign = [](double x, double y) -> double {
|
||||||
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
|
if (fast_float::cpp20_and_in_constexpr()) {
|
||||||
|
using equiv_int = std::make_signed_t<
|
||||||
|
typename fast_float::binary_format<double>::equiv_uint>;
|
||||||
|
const auto i = std::bit_cast<equiv_int>(y);
|
||||||
|
if (i < 0) {
|
||||||
|
return -x;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return std::copysign(x, y);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto isnan = [](double x) -> bool {
|
||||||
|
return x != x;
|
||||||
|
};
|
||||||
|
|
||||||
|
FASTFLOAT_CHECK_EQ(result.ec, std::errc());
|
||||||
|
FASTFLOAT_CHECK_EQ(result.ptr, str.data() + str.size());
|
||||||
|
FASTFLOAT_CHECK_EQ(copysign(1, actual), copysign(1, expected));
|
||||||
|
FASTFLOAT_CHECK_EQ(isnan(actual), isnan(expected));
|
||||||
|
FASTFLOAT_CHECK_EQ(actual, expected);
|
||||||
|
|
||||||
|
#undef FASTFLOAT_CHECK_EQ
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Diag diag, class T>
|
||||||
|
constexpr void basic_test(std::string_view str, T expected) {
|
||||||
T actual;
|
T actual;
|
||||||
auto result = fast_float::from_chars(str.data(), str.data() + str.size(), actual);
|
auto result = fast_float::from_chars(str.data(), str.data() + str.size(), actual);
|
||||||
check_basic_test_result(str, result, actual, expected);
|
check_basic_test_result<diag>(str, result, actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<Diag diag, class T>
|
||||||
void basic_test(std::string str, T expected, fast_float::parse_options options) {
|
constexpr void basic_test(std::string_view str, T expected, fast_float::parse_options options) {
|
||||||
T actual;
|
T actual;
|
||||||
auto result = fast_float::from_chars_advanced(str.data(), str.data() + str.size(), actual, options);
|
auto result = fast_float::from_chars_advanced(str.data(), str.data() + str.size(), actual, options);
|
||||||
check_basic_test_result(str, result, actual, expected);
|
check_basic_test_result<diag>(str, result, actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_test(float val) {
|
void basic_test(float val) {
|
||||||
{
|
{
|
||||||
std::string long_vals = to_long_string(val);
|
std::string long_vals = to_long_string(val);
|
||||||
INFO("long vals: " << long_vals);
|
INFO("long vals: " << long_vals);
|
||||||
basic_test<float>(long_vals, val);
|
basic_test<Diag::runtime, float>(long_vals, val);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::string vals = to_string(val);
|
std::string vals = to_string(val);
|
||||||
INFO("vals: " << vals);
|
INFO("vals: " << vals);
|
||||||
basic_test<float>(vals, val);
|
basic_test<Diag::runtime, float>(vals, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define verify(lhs, rhs) { INFO(lhs); basic_test(lhs, rhs); }
|
#define verify_runtime(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
INFO(lhs); \
|
||||||
|
basic_test<Diag::runtime>(lhs, rhs); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define verify_comptime(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
constexpr int verify_comptime_var = \
|
||||||
|
(basic_test<Diag::comptime>(lhs, rhs), 0); \
|
||||||
|
(void)verify_comptime_var; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define verify_options_runtime(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
INFO(lhs); \
|
||||||
|
basic_test<Diag::runtime>(lhs, rhs, options); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define verify_options_comptime(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
constexpr int verify_options_comptime_var = \
|
||||||
|
(basic_test<Diag::comptime>(lhs, rhs, options), 0); \
|
||||||
|
(void)verify_options_comptime_var; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#if defined(FASTFLOAT_CONSTEXPR_TESTS)
|
||||||
|
#if !FASTFLOAT_IS_CONSTEXPR
|
||||||
|
#error "from_chars must be constexpr for constexpr tests"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define verify(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
verify_runtime(lhs, rhs); \
|
||||||
|
verify_comptime(lhs, rhs); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define verify_options(lhs, rhs) \
|
||||||
|
do { \
|
||||||
|
verify_options_runtime(lhs, rhs); \
|
||||||
|
verify_options_comptime(lhs, rhs); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define verify verify_runtime
|
||||||
|
#define verify_options verify_options_runtime
|
||||||
|
#endif
|
||||||
|
|
||||||
#define verify32(val) { INFO(#val); basic_test(val); }
|
#define verify32(val) { INFO(#val); basic_test(val); }
|
||||||
|
|
||||||
#define verify_options(lhs, rhs) { INFO(lhs); basic_test(lhs, rhs, options); }
|
|
||||||
|
|
||||||
TEST_CASE("64bit.inf") {
|
TEST_CASE("64bit.inf") {
|
||||||
verify("INF", std::numeric_limits<double>::infinity());
|
verify("INF", std::numeric_limits<double>::infinity());
|
||||||
verify("-INF", -std::numeric_limits<double>::infinity());
|
verify("-INF", -std::numeric_limits<double>::infinity());
|
||||||
@ -644,7 +790,7 @@ TEST_CASE("64bit.general") {
|
|||||||
verify("-2.2222222222223e-322",-0x1.68p-1069);
|
verify("-2.2222222222223e-322",-0x1.68p-1069);
|
||||||
verify("9007199254740993.0", 0x1p+53);
|
verify("9007199254740993.0", 0x1p+53);
|
||||||
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
|
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
|
||||||
verify(append_zeros("9007199254740993.0",1000), 0x1p+53);
|
verify_runtime(append_zeros("9007199254740993.0",1000), 0x1p+53);
|
||||||
verify("10000000000000000000", 0x1.158e460913dp+63);
|
verify("10000000000000000000", 0x1.158e460913dp+63);
|
||||||
verify("10000000000000000000000000000001000000000000", 0x1.cb2d6f618c879p+142);
|
verify("10000000000000000000000000000001000000000000", 0x1.cb2d6f618c879p+142);
|
||||||
verify("10000000000000000000000000000000000000000001", 0x1.cb2d6f618c879p+142);
|
verify("10000000000000000000000000000000000000000001", 0x1.cb2d6f618c879p+142);
|
||||||
@ -701,8 +847,11 @@ TEST_CASE("64bit.general") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("64bit.decimal_point") {
|
TEST_CASE("64bit.decimal_point") {
|
||||||
fast_float::parse_options options{};
|
constexpr auto options = []{
|
||||||
options.decimal_point = ',';
|
fast_float::parse_options ret{};
|
||||||
|
ret.decimal_point = ',';
|
||||||
|
return ret;
|
||||||
|
}();
|
||||||
|
|
||||||
// infinities
|
// infinities
|
||||||
verify_options("1,8e308", std::numeric_limits<double>::infinity());
|
verify_options("1,8e308", std::numeric_limits<double>::infinity());
|
||||||
@ -715,7 +864,7 @@ TEST_CASE("64bit.decimal_point") {
|
|||||||
verify_options("-2,2222222222223e-322",-0x1.68p-1069);
|
verify_options("-2,2222222222223e-322",-0x1.68p-1069);
|
||||||
verify_options("9007199254740993,0", 0x1p+53);
|
verify_options("9007199254740993,0", 0x1p+53);
|
||||||
verify_options("860228122,6654514319E+90", 0x1.92bb20990715fp+328);
|
verify_options("860228122,6654514319E+90", 0x1.92bb20990715fp+328);
|
||||||
verify_options(append_zeros("9007199254740993,0",1000), 0x1p+53);
|
verify_options_runtime(append_zeros("9007199254740993,0",1000), 0x1p+53);
|
||||||
verify_options("1,1920928955078125e-07", 1.1920928955078125e-07);
|
verify_options("1,1920928955078125e-07", 1.1920928955078125e-07);
|
||||||
verify_options("9355950000000000000,00000000000000000000000000000000001844674407370955161600000184467440737095516161844674407370955161407370955161618446744073709551616000184467440737095516166000001844674407370955161618446744073709551614073709551616184467440737095516160001844674407370955161601844674407370955674451616184467440737095516140737095516161844674407370955161600018446744073709551616018446744073709551611616000184467440737095001844674407370955161600184467440737095516160018446744073709551168164467440737095516160001844073709551616018446744073709551616184467440737095516160001844674407536910751601611616000184467440737095001844674407370955161600184467440737095516160018446744073709551616184467440737095516160001844955161618446744073709551616000184467440753691075160018446744073709",0x1.03ae05e8fca1cp+63);
|
verify_options("9355950000000000000,00000000000000000000000000000000001844674407370955161600000184467440737095516161844674407370955161407370955161618446744073709551616000184467440737095516166000001844674407370955161618446744073709551614073709551616184467440737095516160001844674407370955161601844674407370955674451616184467440737095516140737095516161844674407370955161600018446744073709551616018446744073709551611616000184467440737095001844674407370955161600184467440737095516160018446744073709551168164467440737095516160001844073709551616018446744073709551616184467440737095516160001844674407536910751601611616000184467440737095001844674407370955161600184467440737095516160018446744073709551616184467440737095516160001844955161618446744073709551616000184467440753691075160018446744073709",0x1.03ae05e8fca1cp+63);
|
||||||
verify_options("2,22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984375e-308", 0x1.0000000000002p-1022);
|
verify_options("2,22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984375e-308", 0x1.0000000000002p-1022);
|
||||||
@ -778,16 +927,16 @@ TEST_CASE("32bit.general") {
|
|||||||
verify("-1e-999",-0.0f);
|
verify("-1e-999",-0.0f);
|
||||||
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
||||||
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
||||||
verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
verify_runtime(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
||||||
verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced3p+0f);
|
verify_runtime(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced3p+0f);
|
||||||
verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced3p+0f);
|
verify_runtime(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced3p+0f);
|
||||||
std::string test_string;
|
std::string test_string;
|
||||||
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655) + std::string("e-38");
|
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655) + std::string("e-38");
|
||||||
verify(test_string, 0x1.fffff8p-127f);
|
verify_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656) + std::string("e-38");
|
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656) + std::string("e-38");
|
||||||
verify(test_string, 0x1.fffff8p-127f);
|
verify_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000) + std::string("e-38");
|
test_string = append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000) + std::string("e-38");
|
||||||
verify(test_string, 0x1.fffff8p-127f);
|
verify_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
verify32(1.00000006e+09f);
|
verify32(1.00000006e+09f);
|
||||||
verify32(1.4012984643e-45f);
|
verify32(1.4012984643e-45f);
|
||||||
verify32(1.1754942107e-38f);
|
verify32(1.1754942107e-38f);
|
||||||
@ -852,8 +1001,11 @@ TEST_CASE("32bit.general") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("32bit.decimal_point") {
|
TEST_CASE("32bit.decimal_point") {
|
||||||
fast_float::parse_options options{};
|
constexpr auto options = [] {
|
||||||
options.decimal_point = ',';
|
fast_float::parse_options ret{};
|
||||||
|
ret.decimal_point = ',';
|
||||||
|
return ret;
|
||||||
|
}();
|
||||||
|
|
||||||
// infinity
|
// infinity
|
||||||
verify_options("3,5028234666e38", std::numeric_limits<float>::infinity());
|
verify_options("3,5028234666e38", std::numeric_limits<float>::infinity());
|
||||||
@ -861,16 +1013,16 @@ TEST_CASE("32bit.decimal_point") {
|
|||||||
// finites
|
// finites
|
||||||
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
||||||
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
||||||
verify_options(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
verify_options_runtime(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
||||||
verify_options(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced3p+0f);
|
verify_options_runtime(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced3p+0f);
|
||||||
verify_options(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced3p+0f);
|
verify_options_runtime(append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced3p+0f);
|
||||||
std::string test_string;
|
std::string test_string;
|
||||||
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655) + std::string("e-38");
|
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655) + std::string("e-38");
|
||||||
verify_options(test_string, 0x1.fffff8p-127f);
|
verify_options_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656) + std::string("e-38");
|
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656) + std::string("e-38");
|
||||||
verify_options(test_string, 0x1.fffff8p-127f);
|
verify_options_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000) + std::string("e-38");
|
test_string = append_zeros("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000) + std::string("e-38");
|
||||||
verify_options(test_string, 0x1.fffff8p-127f);
|
verify_options_runtime(test_string, 0x1.fffff8p-127f);
|
||||||
verify_options("1,1754943508e-38", 1.1754943508e-38f);
|
verify_options("1,1754943508e-38", 1.1754943508e-38f);
|
||||||
verify_options("30219,0830078125", 30219.0830078125f);
|
verify_options("30219,0830078125", 30219.0830078125f);
|
||||||
verify_options("1,1754947011469036e-38", 0x1.000006p-126f);
|
verify_options("1,1754947011469036e-38", 0x1.000006p-126f);
|
||||||
|
|||||||
@ -62,6 +62,7 @@ void random_values(size_t N) {
|
|||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (std::isnan(v)) {
|
if (std::isnan(v)) {
|
||||||
if (!std::isnan(result_value)) {
|
if (!std::isnan(result_value)) {
|
||||||
|
|||||||
@ -65,6 +65,7 @@ void random_values(size_t N) {
|
|||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (std::isnan(v)) {
|
if (std::isnan(v)) {
|
||||||
if (!std::isnan(result_value)) {
|
if (!std::isnan(result_value)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user