Instead of making assumptions about the representation of float and unsigned int, including size and endianness and encoding, you should use the fpclassify macro defined in <math.h> specifically designed for this purpose:
int is_denorm(float f) {
return fpclassify(f) == FP_SUBNORMAL;
}
Depending on its argument, fpclassify(x) evaluates to one of the number classification macros:
FP_INFINITE
FP_NAN
FP_NORMAL
FP_SUBNORMAL
FP_ZERO
They represent the mutually exclusive kinds of floating-point values. They expand to integer constant expressions with distinct values. Additional implementation-defined floating-point classifications, with macro definitions beginning with FP_ and an uppercase letter, may also be specified by the implementation.
The signbit macro can be used to extract the sign of a floating point value (of type float, double or long double). Note that signbit(x) evaluates to non zero for negative values and non-values, including -0.0 for which x < 0 would evaluate to false.
Note that your approach has some problems even on architectures using IEEE 754 single precision floats and 32-bit integers with the same endianness:
- to avoid aliasing issues, instead of
unsigned int x = *(int *)&f; you should write uint32_t x; memcpy(&x, &f, sizeof x);
- testing the exponent bits is not sufficient to detect subnormal values as the values
0.0 and -0.0 also have all exponent bits set to 0.
Also note that denormalized is not always the same as subnormal: In the IEEE 754 standard, subnormal refers to non zero numbers smaller in magnitude than normal numbers with an implicit 1 mantissa (denormal is not used anymore in the IEEE 754 standard nor in the C Standard). Other floating point standards with multiple representations may have denormalized numbers for other sets of values.