2

Is there any way to get NaNs from the Windows CRT string to float functions?


Why: I'm writing an IEEE float to string converter in C with no information loss (strtod, sscanf or atof return the original float) provided the rounding mode doesn't change.

I'm under MinGW or Visual C++, so these calls go to the MSVC++ runtime. The problem is that I can't get it to parse any special values (like "Inf" or "NaN"). Inf is OK (it's returned after parsing a value that doesn't fit in a float, such as "1e999").

  /* Return the shortest string representation of a float with a successful scanf round-trip.
   * Guaranteed to fit in 13 chars (including the final '\0').
   */
  char* ftoa(char* res, float f) {
     float r = 0;
     int i, j, len, e = floor(log10(f)) + 1;
     char fmt[8];
     union { float f; int32_t i; } u = { f } ;

     if (f > FLT_MAX) { sprintf(res, "1e999"); return res; }
     if (f < -FLT_MAX) { sprintf(res, "-1e999"); return res; }

     if ((u.i & 0x7F800000) == 0x7F800000) {  // NaN
        sprintf(res, u.i == 0x7FC00000 ? "%sNaN" : "%sNaN%d", u.i<0 ? "-" : "", u.i & 0x7FFFFF);
        return res;
     }  

     // compute the shortest string without exponent ("123000", "0.15")
     if (!f || e>-4 && e<10) {
        for (i=0; i<=10; i++) {
           sprintf(fmt, "%%.%df", i);
           sprintf(res, fmt, f);
           sscanf(res, "%f", &r); if (r==f) break;
        }
     }
     if (r==f) len = strlen(res);
     else len = 1e9;

     if (!f) return res;  // handle 0 and -0

     // compute the shortest string with exponent ("123e3", "15e-2")
     for (i=0; i<9; i++) {
        sprintf(res, "%.0fe%d", f * pow(10,-e), e); sscanf(res, "%f", &r); if (r==f) break;
        j = strlen(res); if (j >= lenF) break;
        while (res[j] != 'e') j--;
        res[j-1]--; sscanf(res, "%f", &r); if (r==f) break;  // try +-1
        res[j-1]+=2; sscanf(res, "%f", &r); if (r==f) break;
        e--;
     }
     if (len <= strlen(res)) sprintf(res, fmt, f);
     return res;
  }
Řrřola
  • 6,007
  • 1
  • 17
  • 10
  • Either you need the original number back bit-for-bit, or you don't need to preserve payload bits. Both can't be true. Also, this feature of an encoder/decoder pair is called "round-tripping", not lossless. *Lossless* would refer to the encoding itself, not the function for creating it. – Ben Voigt Aug 08 '11 at 21:14
  • @BenVoigt Thank for the input, reformulated. Actually it turns out I needed to preserve the payload bits. – Řrřola Aug 08 '11 at 21:52
  • Solution using `boost::math::nonfinite_num_get/put`: http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/fp_facets/intro.html – Řrřola Aug 08 '11 at 22:36

1 Answers1

1

No. They return HUGE_VAL if overflow would occur and 0 if the input can't be parsed or underflow occurs.

Carey Gregory
  • 6,836
  • 2
  • 26
  • 47
  • Thanks. If that's correct, it's bad news. I guess I'm gonna need a wrapper around `strtod` that tests for NaNs. – Řrřola Aug 08 '11 at 21:18