cfloating-pointconstantsc11c17

How to determine w/o conversions that a given floating constant can be represented?


How to determine w/o conversions that a given floating constant can be represented?

Sample code:

#define FLOATING_CONSTANT1  2147483647.0f
#define FLOATING_CONSTANT2  2147483520.0f

bool b1 = FLOATING_CONSTANT_CAN_BE_REPRESENTED( FLOATING_CONSTANT1 );  // false
bool b2 = FLOATING_CONSTANT_CAN_BE_REPRESENTED( FLOATING_CONSTANT2 );  // true

Solution

  • "w/o conversions" seems to be an unnecessary restrictive requirement, but something to get OP started and a test harness for others.


    #define str(s) #s
    #define xstr(s) str(s)
    #define FLOATING_CONSTANT_CAN_BE_REPRESENTED(fc1) float_const_test(xstr(fc1), fc1)
    
    bool float_const_test(const char *s, float f1) {
      printf("<%s> %g\n", s, f1);
      char *endptr;
      errno = 0;
      double d2 = strtod(s, &endptr);
      if (s == endptr) return false;
      if (strcmp(endptr, "f") && strcmp(endptr, "F")) return false;
      if (f1 != d2) return false;
      // Note a 100% here, the string may have rounded to a double.
      return true;
    }
    
    int main(void) {
      puts("Good");
      printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.5f));
      printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(0x1.5p0f));
      puts("\nBad");
      printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.23f));
      printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.23e40f));
    }
    

    Output

    Good
    <1.5f> 1.5
    1
    <0x1.5p0f> 1.3125
    1
    
    Bad
    <1.23f> 1.23
    0
    <1.23e40f> inf
    0
    

    Notes:

    If the fractional portion of a FP constant does not end in 5 or 0, it cannot be exactly converted to a float/double.

    When exact FP constants are needed, the first step is to consider hexadecimal-floating-constant such a 0x1.23CDp12f