Minor cleaning.

This commit is contained in:
Daniel Lemire 2020-11-02 21:42:01 -05:00
parent 2e1d8ba899
commit 288efd35eb
2 changed files with 72 additions and 97 deletions

View File

@ -14,9 +14,6 @@
namespace fast_float { namespace fast_float {
// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating // This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating
// the result, with the "high" part corresponding to the most significant bits and the // the result, with the "high" part corresponding to the most significant bits and the
// low part corresponding to the least significant bits. // low part corresponding to the least significant bits.
@ -91,7 +88,7 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
// 2. We need an extra bit for rounding purposes // 2. We need an extra bit for rounding purposes
// 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift) // 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift)
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w); value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
if(product.low == 0xFFFFFFFFFFFFFFFF) { // could guard it further if(product.low == 0xFFFFFFFFFFFFFFFF) { // could guard it further
// In some very rare cases, this could happen, in which case we might need a more accurate // In some very rare cases, this could happen, in which case we might need a more accurate
// computation that what we can provide cheaply. This is very, very unlikely. // computation that what we can provide cheaply. This is very, very unlikely.
answer.power2 = -1; // This (a negative value) indicates an error condition. answer.power2 = -1; // This (a negative value) indicates an error condition.

View File

@ -3,10 +3,6 @@
#include <cfloat> #include <cfloat>
#include <cstdint> #include <cstdint>
#ifndef _WIN32
// strcasecmp, strncasecmp
#include <strings.h>
#endif
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
#define FASTFLOAT_VISUAL_STUDIO 1 #define FASTFLOAT_VISUAL_STUDIO 1
@ -16,14 +12,15 @@
#define fastfloat_really_inline __forceinline #define fastfloat_really_inline __forceinline
#else #else
#define fastfloat_really_inline inline __attribute__((always_inline)) #define fastfloat_really_inline inline __attribute__((always_inline))
#endif #endif
namespace fast_float { namespace fast_float {
// Compares two ASCII strings in a case insensitive manner. // Compares two ASCII strings in a case insensitive manner.
inline bool fastfloat_strncasecmp(const char * input1, const char * input2, size_t length) { inline bool fastfloat_strncasecmp(const char *input1, const char *input2,
size_t length) {
char running_diff{0}; char running_diff{0};
for(size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
running_diff |= (input1[i] ^ input2[i]); running_diff |= (input1[i] ^ input2[i]);
} }
return (running_diff == 0) || (running_diff == 32); return (running_diff == 0) || (running_diff == 32);
@ -33,14 +30,20 @@ inline bool fastfloat_strncasecmp(const char * input1, const char * input2, size
#error "FLT_EVAL_METHOD should be defined, please include cfloat." #error "FLT_EVAL_METHOD should be defined, please include cfloat."
#endif #endif
bool is_space(uint8_t c) { bool is_space(uint8_t c) {
static const bool table[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const bool table[] = {
return table[c]; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
return table[c];
} }
namespace { namespace {
@ -49,7 +52,6 @@ constexpr uint32_t max_digit_without_overflow = 19;
constexpr int32_t decimal_point_range = 2047; constexpr int32_t decimal_point_range = 2047;
} // namespace } // namespace
struct value128 { struct value128 {
uint64_t low; uint64_t low;
uint64_t high; uint64_t high;
@ -57,10 +59,8 @@ struct value128 {
value128() : low(0), high(0) {} value128() : low(0), high(0) {}
}; };
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
fastfloat_really_inline fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
int leading_zeroes(uint64_t input_num) {
#ifdef FASTFLOAT_VISUAL_STUDIO #ifdef FASTFLOAT_VISUAL_STUDIO
unsigned long leading_zero = 0; unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB) // Search the mask data from most significant bit (MSB)
@ -74,18 +74,18 @@ int leading_zeroes(uint64_t input_num) {
#endif #endif
} }
#if defined(_WIN32) && !defined(__clang__) #if defined(_WIN32) && !defined(__clang__)
// Note MinGW falls here too // Note MinGW falls here too
#include <intrin.h> #include <intrin.h>
#if !defined(_M_X64) && !defined(_M_ARM64)// _umul128 for x86, arm #if !defined(_M_X64) && !defined(_M_ARM64) // _umul128 for x86, arm
// this is a slow emulation routine for 32-bit Windows // this is a slow emulation routine for 32-bit Windows
// //
fastfloat_really_inline uint64_t __emulu(uint32_t x, uint32_t y) { fastfloat_really_inline uint64_t __emulu(uint32_t x, uint32_t y) {
return x * (uint64_t)y; return x * (uint64_t)y;
} }
fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
uint64_t *hi) {
uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd); uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd);
uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd); uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd);
uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32)); uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
@ -97,14 +97,16 @@ fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi
} }
#endif #endif
fastfloat_really_inline value128 full_multiplication(uint64_t value1, uint64_t value2) { fastfloat_really_inline value128 full_multiplication(uint64_t value1,
uint64_t value2) {
value128 answer; value128 answer;
#ifdef _M_ARM64 #ifdef _M_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate // ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2); answer.high = __umulh(value1, value2);
answer.low = value1 * value2; answer.low = value1 * value2;
#else #else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64 answer.low =
_umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64 #endif // _M_ARM64
return answer; return answer;
} }
@ -112,8 +114,8 @@ fastfloat_really_inline value128 full_multiplication(uint64_t value1, uint64_t v
#else #else
// compute value1 * value2 // compute value1 * value2
fastfloat_really_inline fastfloat_really_inline value128 full_multiplication(uint64_t value1,
value128 full_multiplication(uint64_t value1, uint64_t value2) { uint64_t value2) {
value128 answer; value128 answer;
__uint128_t r = ((__uint128_t)value1) * value2; __uint128_t r = ((__uint128_t)value1) * value2;
answer.low = uint64_t(r); answer.low = uint64_t(r);
@ -125,9 +127,9 @@ value128 full_multiplication(uint64_t value1, uint64_t value2) {
struct adjusted_mantissa { struct adjusted_mantissa {
uint64_t mantissa; uint64_t mantissa;
int power2;// a negative value indicate an invalid result int power2; // a negative value indicate an invalid result
adjusted_mantissa() = default; adjusted_mantissa() = default;
//bool operator==(const adjusted_mantissa &o) const = default; // bool operator==(const adjusted_mantissa &o) const = default;
bool operator==(const adjusted_mantissa &o) const { bool operator==(const adjusted_mantissa &o) const {
return mantissa == o.mantissa && power2 == o.power2; return mantissa == o.mantissa && power2 == o.power2;
} }
@ -143,46 +145,47 @@ struct decimal {
// Copies are not allowed since this is a fat object. // Copies are not allowed since this is a fat object.
decimal(const decimal &) = delete; decimal(const decimal &) = delete;
// Copies are not allowed since this is a fat object. // Copies are not allowed since this is a fat object.
decimal & operator=(const decimal &) = delete; decimal &operator=(const decimal &) = delete;
// Moves are allowed: // Moves are allowed:
decimal(decimal &&) = default; decimal(decimal &&) = default;
decimal& operator=(decimal&& other) = default; decimal &operator=(decimal &&other) = default;
// Generates a mantissa by truncating to 19 digits; this function assumes // Generates a mantissa by truncating to 19 digits; this function assumes
// that num_digits >= 19 (the caller is responsible for the check). // that num_digits >= 19 (the caller is responsible for the check).
// This function should be reasonably fast. // This function should be reasonably fast.
inline uint64_t to_truncated_mantissa() { inline uint64_t to_truncated_mantissa() {
uint64_t val; uint64_t val;
// 8 first digits // 8 first digits
::memcpy(&val, digits, sizeof(uint64_t)); ::memcpy(&val, digits, sizeof(uint64_t));
val = val * 2561 >> 8; val = val * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
uint64_t mantissa = uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); uint64_t mantissa =
uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
// 8 more digits for a total of 16 // 8 more digits for a total of 16
::memcpy(&val, digits + sizeof(uint64_t), sizeof(uint64_t)); ::memcpy(&val, digits + sizeof(uint64_t), sizeof(uint64_t));
val = val * 2561 >> 8; val = val * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
uint32_t eight_digits_value = uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); uint32_t eight_digits_value =
uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
mantissa = 100000000 * mantissa + eight_digits_value; mantissa = 100000000 * mantissa + eight_digits_value;
for(uint32_t i = 2*sizeof(uint64_t); i < max_digit_without_overflow; i++) { for (uint32_t i = 2 * sizeof(uint64_t); i < max_digit_without_overflow;
i++) {
mantissa = mantissa * 10 + digits[i]; // can be accelerated mantissa = mantissa * 10 + digits[i]; // can be accelerated
} }
return mantissa; return mantissa;
} }
// Generate san exponent matching to_truncated_mantissa() // Generate san exponent matching to_truncated_mantissa()
inline int32_t to_truncated_exponent() { inline int32_t to_truncated_exponent() {
return decimal_point - max_digit_without_overflow; return decimal_point - max_digit_without_overflow;
} }
}; };
constexpr static double powers_of_ten_double[] = { constexpr static double powers_of_ten_double[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
constexpr static float powers_of_ten_float[] = { constexpr static float powers_of_ten_float[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10}; 1e6, 1e7, 1e8, 1e9, 1e10};
template <typename T> template <typename T> struct binary_format {
struct binary_format {
static constexpr int mantissa_explicit_bits(); static constexpr int mantissa_explicit_bits();
static constexpr int minimum_exponent(); static constexpr int minimum_exponent();
static constexpr int infinite_power(); static constexpr int infinite_power();
@ -195,73 +198,54 @@ struct binary_format {
static constexpr T exact_power_of_ten(int64_t power); static constexpr T exact_power_of_ten(int64_t power);
}; };
template <> template <> constexpr int binary_format<double>::mantissa_explicit_bits() {
constexpr int binary_format<double>::mantissa_explicit_bits() {
return 52; return 52;
} }
template <> template <> constexpr int binary_format<float>::mantissa_explicit_bits() {
constexpr int binary_format<float>::mantissa_explicit_bits() {
return 23; return 23;
} }
template <> template <> constexpr int binary_format<double>::max_exponent_round_to_even() {
constexpr int binary_format<double>::max_exponent_round_to_even() {
return 23; return 23;
} }
template <> template <> constexpr int binary_format<float>::max_exponent_round_to_even() {
constexpr int binary_format<float>::max_exponent_round_to_even() {
return 10; return 10;
} }
template <> constexpr int binary_format<double>::min_exponent_round_to_even() {
template <>
constexpr int binary_format<double>::min_exponent_round_to_even() {
return -4; return -4;
} }
template <> template <> constexpr int binary_format<float>::min_exponent_round_to_even() {
constexpr int binary_format<float>::min_exponent_round_to_even() {
return -17; return -17;
} }
template <> template <> constexpr int binary_format<double>::minimum_exponent() {
constexpr int binary_format<double>::minimum_exponent() {
return -1023; return -1023;
} }
template <> template <> constexpr int binary_format<float>::minimum_exponent() {
constexpr int binary_format<float>::minimum_exponent() {
return -127; return -127;
} }
template <> template <> constexpr int binary_format<double>::infinite_power() {
constexpr int binary_format<double>::infinite_power() { return 0x7FF;
return 0x7FF;
} }
template <> template <> constexpr int binary_format<float>::infinite_power() {
constexpr int binary_format<float>::infinite_power() {
return 0xFF; return 0xFF;
} }
template <> template <> constexpr int binary_format<double>::sign_index() { return 63; }
constexpr int binary_format<double>::sign_index() { template <> constexpr int binary_format<float>::sign_index() { return 31; }
return 63;
}
template <>
constexpr int binary_format<float>::sign_index() {
return 31;
}
template <> template <> constexpr int binary_format<double>::min_exponent_fast_path() {
constexpr int binary_format<double>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
return 0; return 0;
#else #else
return -22; return -22;
#endif #endif
} }
template <> template <> constexpr int binary_format<float>::min_exponent_fast_path() {
constexpr int binary_format<float>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
return 0; return 0;
#else #else
@ -269,28 +253,22 @@ constexpr int binary_format<float>::min_exponent_fast_path() {
#endif #endif
} }
template <> constexpr int binary_format<double>::max_exponent_fast_path() {
template <>
constexpr int binary_format<double>::max_exponent_fast_path() {
return 22; return 22;
} }
template <> template <> constexpr int binary_format<float>::max_exponent_fast_path() {
constexpr int binary_format<float>::max_exponent_fast_path() {
return 10; return 10;
} }
template <> constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
template <>
constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits(); return uint64_t(2) << mantissa_explicit_bits();
} }
template <> template <> constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits(); return uint64_t(2) << mantissa_explicit_bits();
} }
template <> template <>
constexpr double binary_format<double>::exact_power_of_ten(int64_t power) { constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
return powers_of_ten_double[power]; return powers_of_ten_double[power];
} }
template <> template <>
@ -299,17 +277,17 @@ constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
return powers_of_ten_float[power]; return powers_of_ten_float[power];
} }
} // namespace fast_float } // namespace fast_float
// for convenience: // for convenience:
#include <ostream> #include <ostream>
std::ostream& operator<<(std::ostream& out, const fast_float::decimal& d) { std::ostream &operator<<(std::ostream &out, const fast_float::decimal &d) {
out << "0."; out << "0.";
for(size_t i = 0; i < d.num_digits; i++) { out << int32_t(d.digits[i]); } for (size_t i = 0; i < d.num_digits; i++) {
out << " * 10 ** " << d.decimal_point; out << int32_t(d.digits[i]);
return out; }
out << " * 10 ** " << d.decimal_point;
return out;
} }
#endif #endif