I have a program which uses fixed point numbers, because the CPU I'm using doesn't support IEEE754 floats.
I've been doing fine with first converting standard IEEE754s into fixed points by finding the exponent, then shifting the number and so on by manually accessing the bits of the said IEE754 float inside the memory. After conversion, I'm able to do fixed-point calculations just fine.
However, is it possible to reconstruct a fixed point (say a Q15.16 integer) back to a IEE754 floating point without FPO so that CPUs with IEEE754/FPO support would be able to read it as their native float type? Is anywhere code or examples of how the CPU's FPO unit actually does this conversion in raw byte manipulation, or is it just some black magic that cannot be done in software? Obviously, I'm not looking for super-precise conversion.
All the answers I've seen until now use FPO. for example, by first calculating 2^(-num_fraction_bits_in_fixed), which already needs FPO, and then scaling the fixed point to that scaling factor.
Edit: By using EOF's answer as a baseline, I was able to create the following code snippet for reconstructing the IEEE754 float from a fixed point integer (In this example the fixed point is a Q31.32, stored inside a INT64). In the end, I just handled the case of 0 manually, since without it the code would actually return a really small, but still a non-zero value.
Here's the code:
static INT32 count_exponent(UINT64 x)
{
INT32 l = -33;
for (UINT64 i = 0; i < 64; i++)
{
UINT64 test = 1ULL << i;
if (x >= test)
l++;
else
break;
}
return l;
}
UINT32 float_from_fix32(INT64 value)
{
INT64 original_num = (INT64)value;
UINT64 sign = 0;
if (value < 0)
sign = 1;
// remove the signed bit if it's set
INT64 unsigned_ver = value < 0 ? -value : value;
// calculate mantissa
int lz = nlz(unsigned_ver);
UINT64 y = unsigned_ver << (lz + 1);
// Our fixed-point is 64bits wide. 8 is the exponent bits for IEEE754
UINT64 mantissa = y >> (33 + 8);
// get the non-fractal bits, add the exponent bias ( 127 in IEEE754 )
UINT64 non_fractal = (unsigned_ver >> 32);
UINT64 exp = count_exponent(unsigned_ver) + 127;
// construct the final IEEE754 float binary number
// first add the last 23 bits (mantissa)
UINT32 ret = mantissa;
// add exponent
ret |= (exp << 23);
// special case of 0
if(mantissa == 0 && non_fractal == 0)
ret = 0;
// add the sign if needed
if (sign)
ret |= 0x80000000;
return ret;
}