The C library includes a function that does this exact task, frexp
:
int expon;
float mant = frexpf(n, &expon);
printf("%g = %g * 2^%d\n", n, mant, expon);
Another way to do it is with log2f
and exp2f
:
if (n == 0) {
mant = 0;
expon = 0;
} else {
expon = floorf(log2f(fabsf(n)));
mant = n * exp2f(-expon);
}
These two techniques are likely to give different results for the same input. For instance, on my computer the frexpf
technique describes 4 as 0.5 × 23 but the log2f
technique describes 4 as 1 × 22. Both are correct, mathematically speaking. Also, frexp
will give you the exact bits of the mantissa, whereas log2f
and exp2f
will probably round off the last bit or two.
You should know that *(unsigned *)&n
and *(float *)&m
violate the rule against "type punning" and have undefined behavior. If you want to get the integer with the same bit representation as a float, or vice versa, use a union:
union { uint32_t i; float f; } u;
u.f = n;
num = u.i;
(Note: This use of unions is well-defined in C since roughly 2003, but, due to the C++ committee's long-standing habit of not paying sufficient attention to changes going into C, it is not officially well-defined in C++.)
You should also know IEEE floating-point numbers use "biased" exponents. When you initialize a float
variable's mantissa field but leave its exponent field at zero, that gives you the representation of a number with a large negative exponent: in other words, a number so small that printf("%f", n)
will print it as zero. Whenever printf("%f", variable)
prints zero, change %f
to %g
or %a
and rerun the program before assuming that variable
actually is zero.