[libc-commits] [PATCH] D136699: [libc] tighten strtofloat cutoffs

Michael Jones via Phabricator via libc-commits libc-commits at lists.llvm.org
Tue Oct 25 10:14:16 PDT 2022


michaelrj created this revision.
michaelrj added reviewers: sivachandra, lntue.
Herald added subscribers: libc-commits, ecnelises, tschuett.
Herald added projects: libc-project, All.
michaelrj requested review of this revision.

When a number for strtofloat has an exponent that's too big or small, it
doesn't need to be calculated precisely since it is guaranteed to be
either INF or 0.0. This tightens those cutoffs to improve performance.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136699

Files:
  libc/src/__support/str_to_float.h


Index: libc/src/__support/str_to_float.h
===================================================================
--- libc/src/__support/str_to_float.h
+++ libc/src/__support/str_to_float.h
@@ -546,6 +546,35 @@
   return true;
 }
 
+// The upper bound is the highest base-10 exponent that could possibly give a
+// non-inf result for this size of float. The value is
+// log_10(2^(exponent bias)).
+// The generic approximation uses the fact that log_10(2^x) ~= x/3
+template <typename T> constexpr int64_t get_upper_bound() {
+  return static_cast<int64_t>(fputil::FloatProperties<T>::EXPONENT_BIAS) / 3;
+}
+
+template <> constexpr int64_t get_upper_bound<float>() { return 39; }
+
+template <> constexpr int64_t get_upper_bound<double>() { return 309; }
+
+// The lower bound is the largest negative base-10 exponent that could possibly
+// give a non-zero result for this size of float. The value is
+// log_10(2^(exponent bias + mantissa width + intermediate mantissa width))
+// The generic approximation uses the fact that log_10(2^x) ~= x/3
+template <typename T> constexpr int64_t get_lower_bound() {
+  return static_cast<int64_t>(fputil::FloatProperties<T>::EXPONENT_BIAS +
+                              fputil::FloatProperties<T>::MANTISSA_WIDTH +
+                              (sizeof(T) * 8)) /
+         3;
+}
+
+template <> constexpr int64_t get_lower_bound<float>() { return 39 + 6 + 10; }
+
+template <> constexpr int64_t get_lower_bound<double>() {
+  return 309 + 15 + 20;
+}
+
 // Takes a mantissa and base 10 exponent and converts it into its closest
 // floating point type T equivalient. First we try the Eisel-Lemire algorithm,
 // then if that fails then we fall back to a more accurate algorithm for
@@ -561,19 +590,14 @@
   // If the exponent is too large and can't be represented in this size of
   // float, return inf. These bounds are very loose, but are mostly serving as a
   // first pass. Some close numbers getting through is okay.
-  if (exp10 >
-      static_cast<int64_t>(fputil::FloatProperties<T>::EXPONENT_BIAS) / 3) {
+  if (exp10 > get_upper_bound<T>()) {
     *outputMantissa = 0;
     *outputExp2 = fputil::FPBits<T>::MAX_EXPONENT;
     errno = ERANGE;
     return;
   }
   // If the exponent is too small even for a subnormal, return 0.
-  if (exp10 < 0 &&
-      -static_cast<int64_t>(exp10) >
-          static_cast<int64_t>(fputil::FloatProperties<T>::EXPONENT_BIAS +
-                               fputil::FloatProperties<T>::MANTISSA_WIDTH) /
-              2) {
+  if (exp10 < 0 && -static_cast<int64_t>(exp10) > get_lower_bound<T>()) {
     *outputMantissa = 0;
     *outputExp2 = 0;
     errno = ERANGE;
@@ -934,8 +958,8 @@
     }
     char *new_str_end = nullptr;
 
-    BitsType output_mantissa = 0;
-    uint32_t output_exponent = 0;
+    BitsType output_mantissa = ~0;
+    uint32_t output_exponent = ~0;
     if (base == 16) {
       seen_digit = hexadecimal_string_to_float<T>(
           src, DECIMAL_POINT, &new_str_end, &output_mantissa, &output_exponent);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D136699.470545.patch
Type: text/x-patch
Size: 3020 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libc-commits/attachments/20221025/8e2151e6/attachment.bin>


More information about the libc-commits mailing list