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.