aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/c++17/fast_float/fast_float.h
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/src/c++17/fast_float/fast_float.h')
-rw-r--r--libstdc++-v3/src/c++17/fast_float/fast_float.h173
1 files changed, 111 insertions, 62 deletions
diff --git a/libstdc++-v3/src/c++17/fast_float/fast_float.h b/libstdc++-v3/src/c++17/fast_float/fast_float.h
index 31fb88b..5da55e2 100644
--- a/libstdc++-v3/src/c++17/fast_float/fast_float.h
+++ b/libstdc++-v3/src/c++17/fast_float/fast_float.h
@@ -74,7 +74,7 @@ struct parse_options {
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
* the type `fast_float::chars_format`. It is a bitset value: we check whether
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
- * to determine whether we allowe the fixed point and scientific notation respectively.
+ * to determine whether we allow the fixed point and scientific notation respectively.
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
*/
template<typename T>
@@ -98,12 +98,11 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
|| defined(__MINGW64__) \
|| defined(__s390x__) \
- || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) \
- || defined(__EMSCRIPTEN__))
+ || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) )
#define FASTFLOAT_64BIT
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \
|| defined(__arm__) || defined(_M_ARM) \
- || defined(__MINGW32__))
+ || defined(__MINGW32__) || defined(__EMSCRIPTEN__))
#define FASTFLOAT_32BIT
#else
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
@@ -128,7 +127,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
#define FASTFLOAT_VISUAL_STUDIO 1
#endif
-#ifdef __BYTE_ORDER__
+#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define FASTFLOAT_IS_BIG_ENDIAN 0
@@ -271,8 +270,9 @@ fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
fastfloat_really_inline value128 full_multiplication(uint64_t a,
uint64_t b) {
value128 answer;
-#ifdef _M_ARM64
+#if defined(_M_ARM64) && !defined(__MINGW32__)
// ARM64 has native support for 64-bit multiplications, no need to emulate
+ // But MinGW on ARM64 doesn't have native support for 64-bit multiplications
answer.high = __umulh(a, b);
answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))
@@ -307,21 +307,69 @@ constexpr static double powers_of_ten_double[] = {
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
constexpr static float powers_of_ten_float[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,
1e6, 1e7, 1e8, 1e9, 1e10};
+// used for max_mantissa_double and max_mantissa_float
+constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
+// Largest integer value v so that (5**index * v) <= 1<<53.
+// 0x10000000000000 == 1 << 53
+constexpr static uint64_t max_mantissa_double[] = {
+ 0x10000000000000,
+ 0x10000000000000 / 5,
+ 0x10000000000000 / (5 * 5),
+ 0x10000000000000 / (5 * 5 * 5),
+ 0x10000000000000 / (5 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555),
+ 0x10000000000000 / (constant_55555 * 5),
+ 0x10000000000000 / (constant_55555 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * 5 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555),
+ 0x10000000000000 / (constant_55555 * constant_55555 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
+ 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5)};
+ // Largest integer value v so that (5**index * v) <= 1<<24.
+ // 0x1000000 == 1<<24
+ constexpr static uint64_t max_mantissa_float[] = {
+ 0x1000000,
+ 0x1000000 / 5,
+ 0x1000000 / (5 * 5),
+ 0x1000000 / (5 * 5 * 5),
+ 0x1000000 / (5 * 5 * 5 * 5),
+ 0x1000000 / (constant_55555),
+ 0x1000000 / (constant_55555 * 5),
+ 0x1000000 / (constant_55555 * 5 * 5),
+ 0x1000000 / (constant_55555 * 5 * 5 * 5),
+ 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5),
+ 0x1000000 / (constant_55555 * constant_55555),
+ 0x1000000 / (constant_55555 * constant_55555 * 5)};
template <typename T> struct binary_format {
+ using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;
+
static inline constexpr int mantissa_explicit_bits();
static inline constexpr int minimum_exponent();
static inline constexpr int infinite_power();
static inline constexpr int sign_index();
- static inline constexpr int min_exponent_fast_path();
static inline constexpr int max_exponent_fast_path();
static inline constexpr int max_exponent_round_to_even();
static inline constexpr int min_exponent_round_to_even();
- static inline constexpr uint64_t max_mantissa_fast_path();
+ static inline constexpr uint64_t max_mantissa_fast_path(int64_t power);
static inline constexpr int largest_power_of_ten();
static inline constexpr int smallest_power_of_ten();
static inline constexpr T exact_power_of_ten(int64_t power);
static inline constexpr size_t max_digits();
+ static inline constexpr equiv_uint exponent_mask();
+ static inline constexpr equiv_uint mantissa_mask();
+ static inline constexpr equiv_uint hidden_bit_mask();
};
template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() {
@@ -364,21 +412,6 @@ template <> inline constexpr int binary_format<float>::infinite_power() {
template <> inline constexpr int binary_format<double>::sign_index() { return 63; }
template <> inline constexpr int binary_format<float>::sign_index() { return 31; }
-template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
-#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
- return 0;
-#else
- return -22;
-#endif
-}
-template <> inline constexpr int binary_format<float>::min_exponent_fast_path() {
-#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
- return 0;
-#else
- return -10;
-#endif
-}
-
template <> inline constexpr int binary_format<double>::max_exponent_fast_path() {
return 22;
}
@@ -386,11 +419,17 @@ template <> inline constexpr int binary_format<float>::max_exponent_fast_path()
return 10;
}
-template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
- return uint64_t(2) << mantissa_explicit_bits();
+template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) {
+ // caller is responsible to ensure that
+ // power >= 0 && power <= 22
+ //
+ return max_mantissa_double[power];
}
-template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
- return uint64_t(2) << mantissa_explicit_bits();
+template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) {
+ // caller is responsible to ensure that
+ // power >= 0 && power <= 10
+ //
+ return max_mantissa_float[power];
}
template <>
@@ -429,6 +468,33 @@ template <> inline constexpr size_t binary_format<float>::max_digits() {
return 114;
}
+template <> inline constexpr binary_format<float>::equiv_uint
+ binary_format<float>::exponent_mask() {
+ return 0x7F800000;
+}
+template <> inline constexpr binary_format<double>::equiv_uint
+ binary_format<double>::exponent_mask() {
+ return 0x7FF0000000000000;
+}
+
+template <> inline constexpr binary_format<float>::equiv_uint
+ binary_format<float>::mantissa_mask() {
+ return 0x007FFFFF;
+}
+template <> inline constexpr binary_format<double>::equiv_uint
+ binary_format<double>::mantissa_mask() {
+ return 0x000FFFFFFFFFFFFF;
+}
+
+template <> inline constexpr binary_format<float>::equiv_uint
+ binary_format<float>::hidden_bit_mask() {
+ return 0x00800000;
+}
+template <> inline constexpr binary_format<double>::equiv_uint
+ binary_format<double>::hidden_bit_mask() {
+ return 0x0010000000000000;
+}
+
template<typename T>
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
uint64_t word = am.mantissa;
@@ -2410,40 +2476,24 @@ fastfloat_really_inline int32_t scientific_exponent(parsed_number_string& num) n
// 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 {
+ 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();
+ constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
+
adjusted_mantissa am;
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
- if (std::is_same<T, float>::value) {
- constexpr uint32_t exponent_mask = 0x7F800000;
- constexpr uint32_t mantissa_mask = 0x007FFFFF;
- constexpr uint64_t hidden_bit_mask = 0x00800000;
- uint32_t bits;
- ::memcpy(&bits, &value, sizeof(T));
- if ((bits & exponent_mask) == 0) {
- // denormal
- am.power2 = 1 - bias;
- am.mantissa = bits & mantissa_mask;
- } else {
- // normal
- am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
- am.power2 -= bias;
- am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
- }
+ equiv_uint bits;
+ ::memcpy(&bits, &value, sizeof(T));
+ if ((bits & exponent_mask) == 0) {
+ // denormal
+ am.power2 = 1 - bias;
+ am.mantissa = bits & mantissa_mask;
} else {
- constexpr uint64_t exponent_mask = 0x7FF0000000000000;
- constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF;
- constexpr uint64_t hidden_bit_mask = 0x0010000000000000;
- uint64_t bits;
- ::memcpy(&bits, &value, sizeof(T));
- if ((bits & exponent_mask) == 0) {
- // denormal
- am.power2 = 1 - bias;
- am.mantissa = bits & mantissa_mask;
- } else {
- // normal
- am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
- am.power2 -= bias;
- am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
- }
+ // normal
+ am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
+ am.power2 -= bias;
+ am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
}
return am;
@@ -2869,11 +2919,10 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
}
answer.ec = std::errc(); // be optimistic
answer.ptr = pns.lastmatch;
- // Next is Clinger's fast path.
- if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits) {
+ // Next is a modified Clinger's fast path, inspired by Jakub JelĂ­nek's proposal
+ if (pns.exponent >= 0 && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent) && !pns.too_many_digits) {
value = T(pns.mantissa);
- if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
- else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
+ value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
if (pns.negative) { value = -value; }
return answer;
}