You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ap...@apache.org on 2020/11/23 17:45:06 UTC

[arrow] branch master updated: ARROW-10610: [C++] Updated vendored fast_float version to latest

This is an automated email from the ASF dual-hosted git repository.

apitrou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new a15c6fc  ARROW-10610: [C++] Updated vendored fast_float version to latest
a15c6fc is described below

commit a15c6fca57a801a4a28eba1b1f1e11e0860b179a
Author: Antoine Pitrou <an...@python.org>
AuthorDate: Mon Nov 23 18:44:24 2020 +0100

    ARROW-10610: [C++] Updated vendored fast_float version to latest
    
    This should fix the big endian (s390x) CI failures.
    
    Closes #8747 from pitrou/ARROW-10610-fast-float-big-endian
    
    Authored-by: Antoine Pitrou <an...@python.org>
    Signed-off-by: Antoine Pitrou <an...@python.org>
---
 cpp/src/arrow/vendored/fast_float/README.md        |   4 +-
 cpp/src/arrow/vendored/fast_float/ascii_number.h   | 198 +++++--------
 .../arrow/vendored/fast_float/decimal_to_binary.h  |  43 +--
 cpp/src/arrow/vendored/fast_float/fast_float.h     |  15 +-
 cpp/src/arrow/vendored/fast_float/fast_table.h     |  30 +-
 cpp/src/arrow/vendored/fast_float/float_common.h   | 324 +++++++++++++--------
 cpp/src/arrow/vendored/fast_float/parse_number.h   |  43 +--
 ...{thompson_tao.h => simple_decimal_conversion.h} |  52 ++--
 8 files changed, 379 insertions(+), 330 deletions(-)

diff --git a/cpp/src/arrow/vendored/fast_float/README.md b/cpp/src/arrow/vendored/fast_float/README.md
index 4e0728c..d0b249e 100644
--- a/cpp/src/arrow/vendored/fast_float/README.md
+++ b/cpp/src/arrow/vendored/fast_float/README.md
@@ -1,9 +1,7 @@
 The files in this directory are vendored from fast_float
-git changeset `dc46ad4c606dc35cb63c947496a18ef8ab1e0f44`.
+git changeset `70c9b7f884c7f80a9a0e06fa9754c0a2e6a9492e`.
 
 See https://github.com/lemire/fast_float
 
 Changes:
-- fixed include paths
-- disabled unused `print()` function
 - enclosed in `arrow_vendored` namespace.
diff --git a/cpp/src/arrow/vendored/fast_float/ascii_number.h b/cpp/src/arrow/vendored/fast_float/ascii_number.h
index d1f8af4..d41e6f4 100644
--- a/cpp/src/arrow/vendored/fast_float/ascii_number.h
+++ b/cpp/src/arrow/vendored/fast_float/ascii_number.h
@@ -11,40 +11,31 @@
 namespace arrow_vendored {
 namespace fast_float {
 
-fastfloat_really_inline bool is_integer(char c)  noexcept  { return (c >= '0' && c <= '9'); }
+// Next function can be micro-optimized, but compilers are entirely
+// able to optimize it well.
+fastfloat_really_inline bool is_integer(char c)  noexcept  { return c >= '0' && c <= '9'; }
 
 
 // credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
 fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars)  noexcept  {
   uint64_t val;
-  memcpy(&val, chars, sizeof(uint64_t));
+  ::memcpy(&val, chars, sizeof(uint64_t));
   val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
   val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
   return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
 }
 
-fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {
-  uint64_t val;
-  memcpy(&val, chars, 8);
+fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val)  noexcept  {
   return (((val & 0xF0F0F0F0F0F0F0F0) |
            (((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) ==
           0x3333333333333333);
 }
 
 
-fastfloat_really_inline uint32_t parse_four_digits_unrolled(const char *chars)  noexcept  {
-  uint32_t val;
-  memcpy(&val, chars, sizeof(uint32_t));
-  val = (val & 0x0F0F0F0F) * 2561 >> 8;
-  return (val & 0x00FF00FF) * 6553601 >> 16;
-}
-
-fastfloat_really_inline bool is_made_of_four_digits_fast(const char *chars)  noexcept  {
-  uint32_t val;
-  memcpy(&val, chars, 4);
-  return (((val & 0xF0F0F0F0) |
-           (((val + 0x06060606) & 0xF0F0F0F0) >> 4)) ==
-          0x33333333);
+fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {
+  uint64_t val;
+  ::memcpy(&val, chars, 8);
+  return is_made_of_eight_digits_fast(val);
 }
 
 struct parsed_number_string {
@@ -57,7 +48,7 @@ struct parsed_number_string {
 };
 
 
-// Assuming that you use no more than 17 digits, this will
+// Assuming that you use no more than 19 digits, this will
 // parse an ASCII string.
 fastfloat_really_inline
 parsed_number_string parse_number_string(const char *p, const char *pend, chars_format fmt) noexcept {
@@ -81,13 +72,15 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
     // a multiplication by 10 is cheaper than an arbitrary integer
     // multiplication
     i = 10 * i +
-        (*p - '0'); // might overflow, we will handle the overflow later
+        uint64_t(*p - '0'); // might overflow, we will handle the overflow later
     ++p;
   }
   int64_t exponent = 0;
   if ((p != pend) && (*p == '.')) {
     ++p;
     const char *first_after_period = p;
+#if FASTFLOAT_IS_BIG_ENDIAN == 0
+    // Fast approach only tested under little endian systems
     if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
       i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
       p += 8;
@@ -96,6 +89,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
         p += 8;
       }
     }
+#endif
     while ((p != pend) && is_integer(*p)) {
       uint8_t digit = uint8_t(*p - '0');
       ++p;
@@ -110,9 +104,9 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
 
   int32_t digit_count =
       int32_t(p - start_digits - 1); // used later to guard against overflows
-  
-  if ((p != pend) && (('e' == *p) || ('E' == *p))) {
-    if((fmt & chars_format::fixed) && !(fmt & chars_format::scientific)) { return answer; } 
+ 
+  if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {
+    const char * location_of_e = p;
     int64_t exp_number = 0;            // exponential part
     ++p;
     bool neg_exp = false;
@@ -123,18 +117,25 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
       ++p;
     }
     if ((p == pend) || !is_integer(*p)) {
-      return answer;
-    }
-    while ((p != pend) && is_integer(*p)) {
-      uint8_t digit = uint8_t(*p - '0');
-      if (exp_number < 0x10000) {
-        exp_number = 10 * exp_number + digit;
+      if(!(fmt & chars_format::fixed)) {
+        // We are in error.
+        return answer;
       }
-      ++p;
+      // Otherwise, we will be ignoring the 'e'.
+      p = location_of_e;
+    } else {
+      while ((p != pend) && is_integer(*p)) {
+        uint8_t digit = uint8_t(*p - '0');
+        if (exp_number < 0x10000) {
+          exp_number = 10 * exp_number + digit;
+        }
+        ++p;
+      }
+      exponent += (neg_exp ? -exp_number : exp_number);
     }
-    exponent += (neg_exp ? -exp_number : exp_number);
   } else {
-    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; } 
+    // If it scientific and not fixed, we have to bail out.
+    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
   }
   answer.lastmatch = p;
   answer.valid = true;
@@ -163,110 +164,35 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
   return answer;
 }
 
-// This should always succeed since it follows a call to parse_number_string.
-// It assumes that there are more than 19 mantissa digits to parse.
-parsed_number_string parse_truncated_decimal(const char *&p, const char *pend)  noexcept  {
-  parsed_number_string answer;
-  answer.valid = true;
-  answer.negative = (*p == '-');
-  if ((*p == '-') || (*p == '+')) {
-    ++p;
-  }
-  size_t number_of_digits{0};
-
-
-  uint64_t i = 0; 
-
-  while ((p != pend) && is_integer(*p)) {
-    // a multiplication by 10 is cheaper than an arbitrary integer
-    // multiplication
-    if(number_of_digits < 19) {
-
-      uint8_t digit = uint8_t(*p - '0');
-      i = 10 * i + digit;
-      number_of_digits ++;
-    }
-    ++p;
-  }
-  int64_t exponent = 0;
-  if ((p != pend) && (*p == '.')) {
-    ++p;
-    const char *first_after_period = p;
-   
-    while ((p != pend) && is_integer(*p)) {
-      if(number_of_digits < 19) {
-        uint8_t digit = uint8_t(*p - '0');
-        i = i * 10 + digit;
-        number_of_digits ++;
-      } else if (exponent == 0) {
-        exponent = first_after_period - p;
-      }
-      ++p;
-    }
-  }
-
-  if ((p != pend) && (('e' == *p) || ('E' == *p))) {
-    int64_t exp_number = 0;            // exponential part
-    ++p;
-    bool neg_exp = false;
-    if ((p != pend) && ('-' == *p)) {
-      neg_exp = true;
-      ++p;
-    } else if ((p != pend) && ('+' == *p)) {
-      ++p;
-    }
-    if ((p == pend) || !is_integer(*p)) {
-      return answer;
-    }
-    while ((p != pend) && is_integer(*p)) {
-      uint8_t digit = uint8_t(*p - '0');
-      if (exp_number < 0x10000) {
-        exp_number = 10 * exp_number + digit;
-      }
-      ++p;
-    }
-    exponent += (neg_exp ? -exp_number : exp_number);
-  } 
-  answer.lastmatch = p;
-  answer.valid = true;
-  answer.too_many_digits = true; // assumed
-  answer.exponent = exponent;
-  answer.mantissa = i;
-  return answer;
-}
-
 
-// This should always succeed since it follows a call to parse_number_string.
-decimal parse_decimal(const char *&p, const char *pend)  noexcept  {
+// This should always succeed since it follows a call to parse_number_string
+// This function could be optimized. In particular, we could stop after 19 digits
+// and try to bail out. Furthermore, we should be able to recover the computed
+// exponent from the pass in parse_number_string.
+fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) noexcept {
   decimal answer;
   answer.num_digits = 0;
   answer.decimal_point = 0;
-  answer.negative = false;
   answer.truncated = false;
-  // skip leading whitespace
-  while (fast_float::is_space(*p)) {
-    p++;
-  }
+  // any whitespace has been skipped.
   answer.negative = (*p == '-');
   if ((*p == '-') || (*p == '+')) {
     ++p;
   }
-
+  // skip leading zeroes
   while ((p != pend) && (*p == '0')) {
     ++p;
   }
   while ((p != pend) && is_integer(*p)) {
-    if (answer.num_digits + 1 < max_digits) {
-      answer.digits[answer.num_digits++] = uint8_t(*p - '0');
-    } else {
-      answer.truncated = true;
+    if (answer.num_digits < max_digits) {
+      answer.digits[answer.num_digits] = uint8_t(*p - '0');
     }
+    answer.num_digits++;
     ++p;
   }
-  const char *first_after_period{};
   if ((p != pend) && (*p == '.')) {
     ++p;
-    first_after_period = p;
+    const char *first_after_period = p;
     // if we have not yet encountered a zero, we have to skip it as well
     if(answer.num_digits == 0) {
       // skip zeros
@@ -274,17 +200,29 @@ decimal parse_decimal(const char *&p, const char *pend)  noexcept  {
        ++p;
       }
     }
+#if FASTFLOAT_IS_BIG_ENDIAN == 0
+    // We expect that this loop will often take the bulk of the running time
+    // because when a value has lots of digits, these digits often
+    while ((p + 8 <= pend) && (answer.num_digits + 8 < max_digits)) {
+      uint64_t val;
+      ::memcpy(&val, p, sizeof(uint64_t));
+      if(! is_made_of_eight_digits_fast(val)) { break; }
+      // We have eight digits, process them in one go!
+      val -= 0x3030303030303030;
+      ::memcpy(answer.digits + answer.num_digits, &val, sizeof(uint64_t));
+      answer.num_digits += 8;
+      p += 8;
+    }
+#endif
     while ((p != pend) && is_integer(*p)) {
-      if (answer.num_digits + 1 < max_digits) {
-        answer.digits[answer.num_digits++] = uint8_t(*p - '0');
-      } else {
-        answer.truncated = true;
+      if (answer.num_digits < max_digits) {
+        answer.digits[answer.num_digits] = uint8_t(*p - '0');
       }
+      answer.num_digits++;
       ++p;
     }
     answer.decimal_point = int32_t(first_after_period - p);
   }
-  
   if ((p != pend) && (('e' == *p) || ('E' == *p))) {
     ++p;
     bool neg_exp = false;
@@ -299,15 +237,23 @@ decimal parse_decimal(const char *&p, const char *pend)  noexcept  {
       uint8_t digit = uint8_t(*p - '0');
       if (exp_number < 0x10000) {
         exp_number = 10 * exp_number + digit;
-      }      
+      }    
       ++p;
     }
     answer.decimal_point += (neg_exp ? -exp_number : exp_number);
   }
-  answer.decimal_point += answer.num_digits;
+  answer.decimal_point += int32_t(answer.num_digits);
+  if(answer.num_digits > max_digits) {
+    answer.truncated = true;
+    answer.num_digits = max_digits;
+  }
+  // In very rare cases, we may have fewer than 19 digits, we want to be able to reliably
+  // assume that all digits up to max_digit_without_overflow have been initialized.
+  for(uint32_t i = answer.num_digits; i < max_digit_without_overflow; i++) { answer.digits[i] = 0; }
+
   return answer;
 }
 } // namespace fast_float
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 
 #endif
diff --git a/cpp/src/arrow/vendored/fast_float/decimal_to_binary.h b/cpp/src/arrow/vendored/fast_float/decimal_to_binary.h
index a64a7aa..d2b5453 100644
--- a/cpp/src/arrow/vendored/fast_float/decimal_to_binary.h
+++ b/cpp/src/arrow/vendored/fast_float/decimal_to_binary.h
@@ -15,24 +15,21 @@
 namespace arrow_vendored {
 namespace fast_float {
 
-
-
-
 // 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
 // low part corresponding to the least significant bits.
-// 
+//
 template <int bit_precision>
 fastfloat_really_inline
 value128 compute_product_approximation(int64_t q, uint64_t w) {
   const int index = 2 * int(q - smallest_power_of_five);
   // For small values of q, e.g., q in [0,27], the answer is always exact because
   // The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
-  // gives the exact answer. 
+  // gives the exact answer.
   value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
   static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should  be in (0,64]");
-  constexpr uint64_t precision_mask = (bit_precision < 64) ? 
-               (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) 
+  constexpr uint64_t precision_mask = (bit_precision < 64) ?
+               (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
                : uint64_t(0xFFFFFFFFFFFFFFFF);
   if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with  (lower + w < lower)
     // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.
@@ -47,29 +44,35 @@ value128 compute_product_approximation(int64_t q, uint64_t w) {
 
 namespace {
 /**
- * For q in (-400,350), we have that
+ * For q in (0,350), we have that
  *  f = (((152170 + 65536) * q ) >> 16);
  * is equal to
  *   floor(p) + q
  * where
  *   p = log(5**q)/log(2) = q * log(5)/log(2)
  *
+ * For negative values of q in (-400,0), we have that 
+ *  f = (((152170 + 65536) * q ) >> 16);
+ * is equal to 
+ *   -ceil(p) + q
+ * where
+ *   p = log(5**-q)/log(2) = -q * log(5)/log(2)
  */
-  fastfloat_really_inline unsigned int power(int q)  noexcept  {
+  fastfloat_really_inline int power(int q)  noexcept  {
     return (((152170 + 65536) * q) >> 16) + 63;
   }
 } // namespace
 
 // w * 10 ** q
 // The returned value should be a valid ieee64 number that simply need to be packed.
-// However, in some very rare cases, the computation will fail. In such cases, we 
+// However, in some very rare cases, the computation will fail. In such cases, we
 // return an adjusted_mantissa with a negative power of 2: the caller should recompute
 // in such cases.
 template <typename binary>
 fastfloat_really_inline
 adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
   adjusted_mantissa answer;
-  if ((w == 0) || (q < smallest_power_of_five) ){
+  if ((w == 0) || (q < smallest_power_of_five)) {
     answer.power2 = 0;
     answer.mantissa = 0;
     // result should be zero
@@ -95,19 +98,18 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
   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
     // computation that what we can provide cheaply. This is very, very unlikely.
-    answer.power2 = -1;
+    answer.power2 = -1; // This (a negative value) indicates an error condition.
     return answer;
   }
   // The "compute_product_approximation" function can be slightly slower than a branchless approach:
   // value128 product = compute_product(q, w);
   // but in practice, we can win big with the compute_product_approximation if its additional branch
   // is easily predicted. Which is best is data specific.
-  uint64_t upperbit = product.high >> 63;
+  int upperbit = int(product.high >> 63);
 
   answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
-  lz += int(1 ^ upperbit);
-  answer.power2 = power(int(q)) - lz - binary::minimum_exponent() + 1;
 
+  answer.power2 = int(power(int(q)) + upperbit - lz - binary::minimum_exponent());
   if (answer.power2 <= 0) { // we have a subnormal?
     // Here have that answer.power2 <= 0 so -answer.power2 >= 0
     if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
@@ -115,8 +117,8 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
       answer.mantissa = 0;
       // result should be zero
       return answer;
-    } 
-    // next line is safe because -answer.power2 + 1 < 0
+    }
+    // next line is safe because -answer.power2 + 1 < 64
     answer.mantissa >>= -answer.power2 + 1;
     // Thankfully, we can't have both "round-to-even" and subnormals because
     // "round-to-even" only occurs for powers close to 0.
@@ -136,13 +138,13 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
   // usually, we round *up*, but if we fall right in between and and we have an
   // even basis, we need to round down
   // We are only concerned with the cases where 5**q fits in single 64-bit word.
-  if ((product.low <= 1) &&  (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) && 
+  if ((product.low <= 1) &&  (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&
       ((answer.mantissa & 3) == 1) ) { // we may fall between two floats!
     // To be in-between two floats we need that in doing
     //   answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
     // ... we dropped out only zeroes. But if this happened, then we can go back!!!
     if((answer.mantissa  << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) ==  product.high) {
-      answer.mantissa &= ~1;          // flip it so that we do not round up
+      answer.mantissa &= ~uint64_t(1);          // flip it so that we do not round up
     }
   }
 
@@ -161,7 +163,8 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
   return answer;
 }
 
+
 } // namespace fast_float
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 
 #endif
diff --git a/cpp/src/arrow/vendored/fast_float/fast_float.h b/cpp/src/arrow/vendored/fast_float/fast_float.h
index 0e7acf5..3e39cac 100644
--- a/cpp/src/arrow/vendored/fast_float/fast_float.h
+++ b/cpp/src/arrow/vendored/fast_float/fast_float.h
@@ -20,19 +20,19 @@ struct from_chars_result {
 
 /**
  * This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
- * a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale. 
- * The resulting floating-point value is the closest floating-point values (using either float or double), 
+ * a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
+ * The resulting floating-point value is the closest floating-point values (using either float or double),
  * using the "round to even" convention for values that would otherwise fall right in-between two values.
  * That is, we provide exact parsing according to the IEEE standard.
- * 
+ *
  * Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
  * parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
  * `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
- * 
+ *
  * The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
- * 
+ *
  * 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 
+ * 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.
  * The default is  `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
@@ -42,6 +42,7 @@ from_chars_result from_chars(const char *first, const char *last,
                              T &value, chars_format fmt = chars_format::general)  noexcept;
 
 }
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
+
 #include "parse_number.h"
 #endif // FASTFLOAT_FAST_FLOAT_H
diff --git a/cpp/src/arrow/vendored/fast_float/fast_table.h b/cpp/src/arrow/vendored/fast_float/fast_table.h
index ac34fe7..97f722a 100644
--- a/cpp/src/arrow/vendored/fast_float/fast_table.h
+++ b/cpp/src/arrow/vendored/fast_float/fast_table.h
@@ -20,18 +20,18 @@ namespace fast_float {
  * The smallest non-zero float (binary64) is 2^−1074.
  * We take as input numbers of the form w x 10^q where w < 2^64.
  * We have that w * 10^-343  <  2^(64-344) 5^-343 < 2^-1076.
- * However, we have that 
+ * However, we have that
  * (2^64-1) * 10^-342 =  (2^64-1) * 2^-342 * 5^-342 > 2^−1074.
- * Thus it is possible for a number of the form w * 10^-342 where 
+ * Thus it is possible for a number of the form w * 10^-342 where
  * w is a 64-bit value to be a non-zero floating-point number.
  *********
- * Any number of form w * 10^309 where w>= 1 is going to be 
+ * Any number of form w * 10^309 where w>= 1 is going to be
  * infinite in binary64 so we never need to worry about powers
  * of 5 greater than 308.
  */
 constexpr int smallest_power_of_five = -342;
 constexpr int largest_power_of_five = 308;
-// truncated powers of five from 5^-344 all the way to 5^308
+// Powers of five from 5^-342 all the way to 5^308 rounded toward one.
 const uint64_t power_of_five_128[]= {
         0xeef453d6923bd65a,0x113faa2906a13b3f,
         0x9558b4661b6565f8,0x4ac7ca59a424c507,
@@ -348,16 +348,16 @@ const uint64_t power_of_five_128[]= {
         0xa2425ff75e14fc31,0xa1258379a94d028d,
         0xcad2f7f5359a3b3e,0x96ee45813a04330,
         0xfd87b5f28300ca0d,0x8bca9d6e188853fc,
-        0x9e74d1b791e07e48,0x775ea264cf55347e,
-        0xc612062576589dda,0x95364afe032a81a0,
-        0xf79687aed3eec551,0x3a83ddbd83f52210,
-        0x9abe14cd44753b52,0xc4926a9672793580,
-        0xc16d9a0095928a27,0x75b7053c0f178400,
-        0xf1c90080baf72cb1,0x5324c68b12dd6800,
-        0x971da05074da7bee,0xd3f6fc16ebca8000,
-        0xbce5086492111aea,0x88f4bb1ca6bd0000,
-        0xec1e4a7db69561a5,0x2b31e9e3d0700000,
-        0x9392ee8e921d5d07,0x3aff322e62600000,
+        0x9e74d1b791e07e48,0x775ea264cf55347d,
+        0xc612062576589dda,0x95364afe032a819d,
+        0xf79687aed3eec551,0x3a83ddbd83f52204,
+        0x9abe14cd44753b52,0xc4926a9672793542,
+        0xc16d9a0095928a27,0x75b7053c0f178293,
+        0xf1c90080baf72cb1,0x5324c68b12dd6338,
+        0x971da05074da7bee,0xd3f6fc16ebca5e03,
+        0xbce5086492111aea,0x88f4bb1ca6bcf584,
+        0xec1e4a7db69561a5,0x2b31e9e3d06c32e5,
+        0x9392ee8e921d5d07,0x3aff322e62439fcf,
         0xb877aa3236a4b449,0x9befeb9fad487c3,
         0xe69594bec44de15b,0x4c2ebe687989a9b4,
         0x901d7cf73ab0acd9,0xf9d37014bf60a11,
@@ -686,6 +686,6 @@ const uint64_t power_of_five_128[]= {
         0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,};
 
 }
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 
 #endif
diff --git a/cpp/src/arrow/vendored/fast_float/float_common.h b/cpp/src/arrow/vendored/fast_float/float_common.h
index 4d82e87..6127fe6 100644
--- a/cpp/src/arrow/vendored/fast_float/float_common.h
+++ b/cpp/src/arrow/vendored/fast_float/float_common.h
@@ -3,47 +3,101 @@
 
 #include <cfloat>
 #include <cstdint>
-#ifndef _WIN32
-// strcasecmp, strncasecmp 
-#include <strings.h>
+#include <cassert>
+
+#if (defined(__i386) || defined(__i386__) || defined(_M_IX86)   \
+     || defined(__arm__)                                        \
+     || defined(__MINGW32__))
+#define FASTFLOAT_32BIT
+#elif (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)   \
+       || defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
+       || defined(__MINGW64__)                                          \
+       || defined(__s390x__)                                            \
+       || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)))
+#define FASTFLOAT_64BIT
+#else
+#error Unknown platform
 #endif
 
-#ifdef _MSC_VER
-#define fastfloat_really_inline __forceinline
-#else
-#define fastfloat_really_inline inline __attribute__((always_inline))
-#endif 
+#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__))
+#include <intrin.h>
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define FASTFLOAT_VISUAL_STUDIO 1
+#endif
 
 #ifdef _WIN32
-#define fastfloat_strcasecmp _stricmp
-#define fastfloat_strncasecmp _strnicmp
+#define FASTFLOAT_IS_BIG_ENDIAN 0
+#else
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <machine/endian.h>
 #else
-#define fastfloat_strcasecmp strcasecmp
-#define fastfloat_strncasecmp strncasecmp
+#include <endian.h>
+#endif
+#
+#ifndef __BYTE_ORDER__
+// safe choice
+#define FASTFLOAT_IS_BIG_ENDIAN 0
+#endif
+#
+#ifndef __ORDER_LITTLE_ENDIAN__
+// safe choice
+#define FASTFLOAT_IS_BIG_ENDIAN 0
+#endif
+#
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define FASTFLOAT_IS_BIG_ENDIAN 0
+#else
+#define FASTFLOAT_IS_BIG_ENDIAN 1
 #endif
-namespace arrow_vendored {
-namespace fast_float {
-#ifndef FLT_EVAL_METHOD
-#error "FLT_EVAL_METHOD should be defined, please include cfloat."
 #endif
 
+#ifdef FASTFLOAT_VISUAL_STUDIO
+#define fastfloat_really_inline __forceinline
+#else
+#define fastfloat_really_inline inline __attribute__((always_inline))
+#endif
 
+namespace arrow_vendored {
+namespace fast_float {
 
+// Compares two ASCII strings in a case insensitive manner.
+inline bool fastfloat_strncasecmp(const char *input1, const char *input2,
+                                  size_t length) {
+  char running_diff{0};
+  for (size_t i = 0; i < length; i++) {
+    running_diff |= (input1[i] ^ input2[i]);
+  }
+  return (running_diff == 0) || (running_diff == 32);
+}
 
+#ifndef FLT_EVAL_METHOD
+#error "FLT_EVAL_METHOD should be defined, please include cfloat."
+#endif
 
-
-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,  [...]
-    return table[c];
+inline 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};
+  return table[c];
 }
 
 namespace {
 constexpr uint32_t max_digits = 768;
-
+constexpr uint32_t max_digit_without_overflow = 19;
 constexpr int32_t decimal_point_range = 2047;
 } // namespace
 
-
 struct value128 {
   uint64_t low;
   uint64_t high;
@@ -51,35 +105,44 @@ struct value128 {
   value128() : low(0), high(0) {}
 };
 
-
 /* result might be undefined when input_num is zero */
-fastfloat_really_inline 
-int leading_zeroes(uint64_t input_num) {
-#ifdef _MSC_VER
+fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
+  assert(input_num > 0);
+#ifdef FASTFLOAT_VISUAL_STUDIO
+  #if defined(_M_X64) || defined(_M_ARM64)
   unsigned long leading_zero = 0;
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
-  if (_BitScanReverse64(&leading_zero, input_num))
-    return (int)(63 - leading_zero);
-  else
-    return 64;
+  _BitScanReverse64(&leading_zero, input_num);
+  return (int)(63 - leading_zero);
+  #else
+  int last_bit = 0;
+  if(input_num & uint64_t(0xffffffff00000000)) input_num >>= 32, last_bit |= 32;
+  if(input_num & uint64_t(        0xffff0000)) input_num >>= 16, last_bit |= 16;
+  if(input_num & uint64_t(            0xff00)) input_num >>=  8, last_bit |=  8;
+  if(input_num & uint64_t(              0xf0)) input_num >>=  4, last_bit |=  4;
+  if(input_num & uint64_t(               0xc)) input_num >>=  2, last_bit |=  2;
+  if(input_num & uint64_t(               0x2)) input_num >>=  1, last_bit |=  1;
+  return 63 - last_bit;
+  #endif
 #else
   return __builtin_clzll(input_num);
 #endif
 }
 
+#ifdef FASTFLOAT_32BIT
 
-#if defined(_WIN32) && !defined(__clang__)
-// Note MinGW falls here too
-#include <intrin.h>
-
-#if !defined(_M_X64) && !defined(_M_ARM64)// _umul128 for x86, arm
-// this is a slow emulation routine for 32-bit Windows
-//
+#if (!defined(_WIN32)) || defined(__MINGW32__)
+// slow emulation routine for 32-bit
 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) {
+#endif
+
+// slow emulation routine for 32-bit
+#if !defined(__MINGW64__)
+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 bd = __emulu((uint32_t)ab, (uint32_t)cd);
   uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
@@ -89,56 +152,103 @@ fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi
         (adbc_carry << 32) + !!(lo < bd);
   return lo;
 }
-#endif
+#endif // !__MINGW64__
 
-fastfloat_really_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  value128 answer;
-#ifdef _M_ARM64
-  // ARM64 has native support for 64-bit multiplications, no need to emultate
-  answer.high = __umulh(value1, value2);
-  answer.low = value1 * value2;
-#else
-  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
-#endif // _M_ARM64
-  return answer;
-}
+#endif // FASTFLOAT_32BIT
 
-#else
 
-// compute value1 * value2
-fastfloat_really_inline
-value128 full_multiplication(uint64_t value1, uint64_t value2) {
+// compute 64-bit a*b
+fastfloat_really_inline value128 full_multiplication(uint64_t a,
+                                                     uint64_t b) {
   value128 answer;
-  __uint128_t r = ((__uint128_t)value1) * value2;
+#ifdef _M_ARM64
+  // ARM64 has native support for 64-bit multiplications, no need to emulate
+  answer.high = __umulh(a, b);
+  answer.low = a * b;
+#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64))
+  answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
+#elif defined(FASTFLOAT_64BIT)
+  __uint128_t r = ((__uint128_t)a) * b;
   answer.low = uint64_t(r);
   answer.high = uint64_t(r >> 64);
+#else
+  #error Not implemented
+#endif
   return answer;
 }
 
-#endif
 
 struct adjusted_mantissa {
-  uint64_t mantissa;
-  int power2;
-  adjusted_mantissa() : mantissa(0), power2(0) {}
+  uint64_t mantissa{0};
+  int power2{0}; // a negative value indicate an invalid result
+  adjusted_mantissa() = default;
+  // bool operator==(const adjusted_mantissa &o) const = default;
+  bool operator==(const adjusted_mantissa &o) const {
+    return mantissa == o.mantissa && power2 == o.power2;
+  }
 };
 
 struct decimal {
-  uint32_t num_digits;
-  int32_t decimal_point;
-  bool negative;
-  bool truncated;
+  uint32_t num_digits{0};
+  int32_t decimal_point{0};
+  bool negative{false};
+  bool truncated{false};
   uint8_t digits[max_digits];
+  decimal() = default;
+  // Copies are not allowed since this is a fat object.
+  decimal(const decimal &) = delete;
+  // Copies are not allowed since this is a fat object.
+  decimal &operator=(const decimal &) = delete;
+  // Moves are allowed:
+  decimal(decimal &&) = default;
+  decimal &operator=(decimal &&other) = default;
+  // Generates a mantissa by truncating to 19 digits.
+  // This function should be reasonably fast.
+  // Note that the user is responsible to ensure that digits are
+  // initialized to zero when there are fewer than 19.
+  inline uint64_t to_truncated_mantissa() {
+#if FASTFLOAT_IS_BIG_ENDIAN == 1
+    uint64_t mantissa = 0;
+    for (uint32_t i = 0; i < max_digit_without_overflow;
+         i++) {
+      mantissa = mantissa * 10 + digits[i]; // can be accelerated
+    }
+    return mantissa;
+#else
+    uint64_t val;
+    // 8 first digits
+    ::memcpy(&val, digits, sizeof(uint64_t));
+    val = val * 2561 >> 8;
+    val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+    uint64_t mantissa =
+        uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
+    // 8 more digits for a total of 16
+    ::memcpy(&val, digits + sizeof(uint64_t), sizeof(uint64_t));
+    val = val * 2561 >> 8;
+    val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+    uint32_t eight_digits_value =
+        uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
+    mantissa = 100000000 * mantissa + eight_digits_value;
+    for (uint32_t i = 2 * sizeof(uint64_t); i < max_digit_without_overflow;
+         i++) {
+      mantissa = mantissa * 10 + digits[i]; // can be accelerated
+    }
+    return mantissa;
+#endif
+  }
+  // Generate san exponent matching to_truncated_mantissa()
+  inline int32_t to_truncated_exponent() {
+    return decimal_point - int32_t(max_digit_without_overflow);
+  }
 };
 
 constexpr static double powers_of_ten_double[] = {
     1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,  1e8,  1e9,  1e10, 1e11,
     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};
+constexpr static float powers_of_ten_float[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,
+                                                1e6, 1e7, 1e8, 1e9, 1e10};
 
-template <typename T>
-struct binary_format {
+template <typename T> struct binary_format {
   static constexpr int mantissa_explicit_bits();
   static constexpr int minimum_exponent();
   static constexpr int infinite_power();
@@ -151,73 +261,54 @@ struct binary_format {
   static constexpr T exact_power_of_ten(int64_t power);
 };
 
-template <>
-constexpr int binary_format<double>::mantissa_explicit_bits() {
+template <> constexpr int binary_format<double>::mantissa_explicit_bits() {
   return 52;
 }
-template <>
-constexpr int binary_format<float>::mantissa_explicit_bits() { 
+template <> constexpr int binary_format<float>::mantissa_explicit_bits() {
   return 23;
 }
 
-template <>
-constexpr int binary_format<double>::max_exponent_round_to_even() {
+template <> constexpr int binary_format<double>::max_exponent_round_to_even() {
   return 23;
 }
 
-template <>
-constexpr int binary_format<float>::max_exponent_round_to_even() {
+template <> constexpr int binary_format<float>::max_exponent_round_to_even() {
   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;
 }
 
-template <>
-constexpr int binary_format<float>::min_exponent_round_to_even() {
+template <> constexpr int binary_format<float>::min_exponent_round_to_even() {
   return -17;
 }
 
-template <>
-constexpr int binary_format<double>::minimum_exponent() { 
+template <> constexpr int binary_format<double>::minimum_exponent() {
   return -1023;
 }
-template <>
-constexpr int binary_format<float>::minimum_exponent() {
+template <> constexpr int binary_format<float>::minimum_exponent() {
   return -127;
 }
 
-template <>
-constexpr int binary_format<double>::infinite_power() {
-  return 0x7FF; 
+template <> constexpr int binary_format<double>::infinite_power() {
+  return 0x7FF;
 }
-template <>
-constexpr int binary_format<float>::infinite_power() { 
+template <> constexpr int binary_format<float>::infinite_power() {
   return 0xFF;
 }
 
-template <>
-constexpr int binary_format<double>::sign_index() { 
-  return 63;
-}
-template <>
-constexpr int binary_format<float>::sign_index() {
-  return 31;
-}
+template <> constexpr int binary_format<double>::sign_index() { return 63; }
+template <> constexpr int binary_format<float>::sign_index() { return 31; }
 
-template <>
-constexpr int binary_format<double>::min_exponent_fast_path() { 
+template <> 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 <>
-constexpr int binary_format<float>::min_exponent_fast_path() {
+template <> constexpr int binary_format<float>::min_exponent_fast_path() {
 #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
   return 0;
 #else
@@ -225,28 +316,22 @@ constexpr int binary_format<float>::min_exponent_fast_path() {
 #endif
 }
 
-
-template <>
-constexpr int binary_format<double>::max_exponent_fast_path() { 
+template <> constexpr int binary_format<double>::max_exponent_fast_path() {
   return 22;
 }
-template <>
-constexpr int binary_format<float>::max_exponent_fast_path() {
+template <> constexpr int binary_format<float>::max_exponent_fast_path() {
   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();
 }
-template <>
-constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
+template <> constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
   return uint64_t(2) << mantissa_explicit_bits();
 }
 
 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];
 }
 template <>
@@ -255,9 +340,18 @@ constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
   return powers_of_ten_float[power];
 }
 
- 
+// for convenience:
+#include <ostream>
+inline std::ostream &operator<<(std::ostream &out, const fast_float::decimal &d) {
+  out << "0.";
+  for (size_t i = 0; i < d.num_digits; i++) {
+    out << int32_t(d.digits[i]);
+  }
+  out << " * 10 ** " << d.decimal_point;
+  return out;
+}
 
 } // namespace fast_float
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 
 #endif
diff --git a/cpp/src/arrow/vendored/fast_float/parse_number.h b/cpp/src/arrow/vendored/fast_float/parse_number.h
index f27a6d8..a570a5c 100644
--- a/cpp/src/arrow/vendored/fast_float/parse_number.h
+++ b/cpp/src/arrow/vendored/fast_float/parse_number.h
@@ -2,7 +2,7 @@
 #define FASTFLOAT_PARSE_NUMBER_H
 #include "ascii_number.h"
 #include "decimal_to_binary.h"
-#include "thompson_tao.h"
+#include "simple_decimal_conversion.h"
 
 #include <cassert>
 #include <cmath>
@@ -17,7 +17,7 @@ namespace fast_float {
 namespace {
 /**
  * Special case +inf, -inf, nan, infinity, -infinity.
- * The case comparisons could be made much faster given that we know that the 
+ * The case comparisons could be made much faster given that we know that the
  * strings a null-free and fixed.
  **/
 template <typename T>
@@ -25,14 +25,13 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value)  n
   from_chars_result answer;
   answer.ec = std::errc(); // be optimistic
   if (last - first >= 3) {
-    if (fastfloat_strncasecmp(first, "nan", 3) == 0) {
+    if (fastfloat_strncasecmp(first, "nan", 3)) {
       answer.ptr = first + 3;
       value = std::numeric_limits<T>::quiet_NaN();
       return answer;
     }
-    if (fastfloat_strncasecmp(first, "inf", 3) == 0) {
-
-      if ((last - first >= 8) && (fastfloat_strncasecmp(first, "infinity", 8) == 0)) {
+    if (fastfloat_strncasecmp(first, "inf", 3)) {
+      if ((last - first >= 8) && fastfloat_strncasecmp(first, "infinity", 8)) {
         answer.ptr = first + 8;
       } else {
         answer.ptr = first + 3;
@@ -41,7 +40,7 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value)  n
       return answer;
     }
     if (last - first >= 4) {
-      if ((fastfloat_strncasecmp(first, "+nan", 4) == 0) || (fastfloat_strncasecmp(first, "-nan", 4) == 0)) {
+      if (fastfloat_strncasecmp(first, "+nan", 4) || fastfloat_strncasecmp(first, "-nan", 4)) {
         answer.ptr = first + 4;
         value = std::numeric_limits<T>::quiet_NaN();
         if (first[0] == '-') {
@@ -50,8 +49,8 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value)  n
         return answer;
       }
 
-      if ((fastfloat_strncasecmp(first, "+inf", 4) == 0) || (fastfloat_strncasecmp(first, "-inf", 4) == 0)) {
-        if ((last - first >= 8) && (fastfloat_strncasecmp(first + 1, "infinity", 8) == 0)) {
+      if (fastfloat_strncasecmp(first, "+inf", 4) || fastfloat_strncasecmp(first, "-inf", 4)) {
+        if ((last - first >= 8) && fastfloat_strncasecmp(first + 1, "infinity", 8)) {
           answer.ptr = first + 9;
         } else {
           answer.ptr = first + 4;
@@ -65,6 +64,7 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value)  n
     }
   }
   answer.ec = std::errc::invalid_argument;
+  answer.ptr = first;
   return answer;
 }
 } // namespace
@@ -78,7 +78,7 @@ from_chars_result from_chars(const char *first, const char *last,
 
 
   from_chars_result answer;
-  while ((first != last) && fast_float::is_space(*first)) {
+  while ((first != last) && fast_float::is_space(uint8_t(*first))) {
     first++;
   }
   if (first == last) {
@@ -95,24 +95,33 @@ from_chars_result from_chars(const char *first, const char *last,
 
   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()) {
     value = T(pns.mantissa);
-    if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); } 
+    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); }
     if (pns.negative) { value = -value; }
     return answer;
   }
   adjusted_mantissa am = pns.too_many_digits ? parse_long_mantissa<binary_format<T>>(first,last) : compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
-  if(am.power2 < 0) {
-    am = parse_long_mantissa<binary_format<T>>(first,last);
-  }
+  // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
+  // then we need to go the long way around again. This is very uncommon.
+  if(am.power2 < 0) { am = parse_long_mantissa<binary_format<T>>(first,last); }
   uint64_t word = am.mantissa;
   word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
-  word = pns.negative 
+  word = pns.negative
   ? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
-  memcpy(&value, &word, sizeof(T));
+#if FASTFLOAT_IS_BIG_ENDIAN == 1
+   if (std::is_same<T, float>::value) {
+     ::memcpy(&value, (char *)&word + 4, sizeof(T)); // extract value at offset 4-7 if float on big-endian
+   } else {
+     ::memcpy(&value, &word, sizeof(T));
+   }
+#else
+   // For little-endian systems:
+   ::memcpy(&value, &word, sizeof(T));
+#endif
   return answer;
 }
 
 } // namespace fast_float
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 
 #endif
diff --git a/cpp/src/arrow/vendored/fast_float/thompson_tao.h b/cpp/src/arrow/vendored/fast_float/simple_decimal_conversion.h
similarity index 91%
rename from cpp/src/arrow/vendored/fast_float/thompson_tao.h
rename to cpp/src/arrow/vendored/fast_float/simple_decimal_conversion.h
index c9ec187..2dc3ee4 100644
--- a/cpp/src/arrow/vendored/fast_float/thompson_tao.h
+++ b/cpp/src/arrow/vendored/fast_float/simple_decimal_conversion.h
@@ -3,14 +3,15 @@
 
 /**
  * This code is meant to handle the case where we have more than 19 digits.
- * 
- * Based on work by Nigel Tao (at https://github.com/google/wuffs/)
+ *
+ * It is based on work by Nigel Tao (at https://github.com/google/wuffs/)
  * who credits Ken Thompson for the design (via a reference to the Go source
- * code). See
- * https://github.com/google/wuffs/blob/aa46859ea40c72516deffa1b146121952d6dfd3b/internal/cgen/base/floatconv-submodule-data.c
- * https://github.com/google/wuffs/blob/46cd8105f47ca07ae2ba8e6a7818ef9c0df6c152/internal/cgen/base/floatconv-submodule-code.c
+ * code).
+ *
+ * Rob Pike suggested that this algorithm be called "Simple Decimal Conversion".
+ *
  * It is probably not very fast but it is a fallback that should almost never
- * be used in reallife.
+ * be used in real life. Though it is not fast, it is "easily" understood and debugged.
  **/
 #include "ascii_number.h"
 #include "decimal_to_binary.h"
@@ -28,22 +29,9 @@ inline void trim(decimal &h) {
   }
 }
 
-#if 0
-/** If you ever want to see what is going on, the following function might prove handy:
- * **/
-void print(const decimal d, int32_t exp2 = 0) {
-  printf("0.");
-  for(size_t i = 0; i < d.num_digits; i++) {
-    printf("%d", int(d.digits[i]));
-  }
-  printf(" * 10 **%d ", d.decimal_point);
-  printf(" * 2 **%d ", exp2);
-}
-#endif
-
 
 
-uint32_t number_of_digits_decimal_left_shift(decimal &h, uint32_t shift) {
+uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t shift) {
   shift &= 63;
   const static uint16_t number_of_digits_decimal_left_shift_table[65] = {
     0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
@@ -136,8 +124,6 @@ uint32_t number_of_digits_decimal_left_shift(decimal &h, uint32_t shift) {
   return num_new_digits;
 }
 
-} // end of anonymous namespace
-
 uint64_t round(decimal &h) {
   if ((h.num_digits == 0) || (h.decimal_point < 0)) {
     return 0;
@@ -152,7 +138,7 @@ uint64_t round(decimal &h) {
   }
   bool round_up = false;
   if (dp < h.num_digits) {
-    round_up = h.digits[dp] >= 5; // normally, we round up    
+    round_up = h.digits[dp] >= 5; // normally, we round up  
     // but we may need to round to even!
     if ((h.digits[dp] == 5) && (dp + 1 == h.num_digits)) {
       round_up = h.truncated || ((dp > 0) && (1 & h.digits[dp - 1]));
@@ -253,6 +239,7 @@ void decimal_right_shift(decimal &h, uint32_t shift) {
   trim(h);
 }
 
+} // end of anonymous namespace
 
 template <typename binary>
 adjusted_mantissa compute_float(decimal &d) {
@@ -266,21 +253,21 @@ adjusted_mantissa compute_float(decimal &d) {
   // At this point, going further, we can assume that d.num_digits > 0.
   //
   // We want to guard against excessive decimal point values because
-  // they can result in long running times. Indeed, we do 
+  // they can result in long running times. Indeed, we do
   // shifts by at most 60 bits. We have that log(10**400)/log(2**60) ~= 22
   // which is fine, but log(10**299995)/log(2**60) ~= 16609 which is not
   // fine (runs for a long time).
   //
   if(d.decimal_point < -324) {
     // We have something smaller than 1e-324 which is always zero
-    // in binary64 and binary32. 
+    // in binary64 and binary32.
     // It should be zero.
     answer.power2 = 0;
     answer.mantissa = 0;
     return answer;
   } else if(d.decimal_point >= 310) {
     // We have something at least as large as 0.1e310 which is
-    // always infinite.    
+    // always infinite.  
     answer.power2 = binary::infinite_power();
     answer.mantissa = 0;
     return answer;
@@ -367,9 +354,20 @@ adjusted_mantissa compute_float(decimal &d) {
 template <typename binary>
 adjusted_mantissa parse_long_mantissa(const char *first, const char* last) {
     decimal d = parse_decimal(first, last);
+    // In some cases we can get lucky and looking at only the first 19 digits is enough.
+    // Let us try that.
+    const uint64_t mantissa = d.to_truncated_mantissa();
+    const int64_t exponent =  d.to_truncated_exponent();
+    // credit: R. Oudompheng who first implemented this fast path (to my knowledge).
+    // It is rough, but it does the job of accelerating the slow path since most
+    // long streams of digits are determined after 19 digits.
+    adjusted_mantissa am1 = compute_float<binary>(exponent, mantissa);
+    adjusted_mantissa am2 = compute_float<binary>(exponent, mantissa+1);
+    // They must both agree and be both a successful result.
+    if(( am1 == am2 ) && (am1.power2 >= 0)) { return am1; }
     return compute_float<binary>(d);
 }
 
 } // namespace fast_float
-}  // namespace arrow_vendored
+} // namespace arrow_vendored
 #endif