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

Michael Jones via Phabricator via libc-commits libc-commits at lists.llvm.org
Tue Oct 25 15:30:50 PDT 2022


michaelrj updated this revision to Diff 470627.
michaelrj marked 2 inline comments as done.
michaelrj added a comment.

Added comments explaining the calculation for the lower bound.
Simplified lower bound logic and moved to int32.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136699/new/

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,41 @@
   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
+// log10(2^(exponent bias)).
+// The generic approximation uses the fact that log10(2^x) ~= x/3
+template <typename T> constexpr int32_t get_upper_bound() {
+  return static_cast<int32_t>(fputil::FloatProperties<T>::EXPONENT_BIAS) / 3;
+}
+
+template <> constexpr int32_t get_upper_bound<float>() { return 39; }
+
+template <> constexpr int32_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
+// log10(2^(exponent bias + final mantissa width + intermediate mantissa width))
+// The intermediate mantissa is the integer that's been parsed from the string,
+// and the final mantissa is the fractional part of the output number. A very
+// low base 10 exponent with a very high intermediate mantissa can cancel each
+// other out, and subnormal numbers allow for the result to be at the very low
+// end of the final mantissa.
+template <typename T> constexpr int32_t get_lower_bound() {
+  return -(static_cast<int32_t>(fputil::FloatProperties<T>::EXPONENT_BIAS +
+                                fputil::FloatProperties<T>::MANTISSA_WIDTH +
+                                (sizeof(T) * 8)) /
+           3);
+}
+
+template <> constexpr int32_t get_lower_bound<float>() {
+  return -(39 + 6 + 10);
+}
+
+template <> constexpr int32_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
@@ -559,21 +594,16 @@
                      typename fputil::FPBits<T>::UIntType *outputMantissa,
                      uint32_t *outputExp2) {
   // 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) {
+  // float, return inf. These bounds are relatively loose, but are mostly
+  // serving as a first pass. Some close numbers getting through is okay.
+  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 < get_lower_bound<T>()) {
     *outputMantissa = 0;
     *outputExp2 = 0;
     errno = ERANGE;
@@ -934,8 +964,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.470627.patch
Type: text/x-patch
Size: 3561 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libc-commits/attachments/20221025/350db6dc/attachment.bin>


More information about the libc-commits mailing list