The display function defined by OP is currently as follows:
void display32Q16 (int32_t num)
{
int16_t integer = num >> 16;
uint64_t fraction = ((0x0000FFFF & num) * 10000) >> 16;
printf("Number = %d.%" PRIu64 "\n", integer, fraction);
}
However, that does not display negative fractions properly because the 2's complement representation of a negative number has most of the bits inverted when compared to the positive number of the same magnitude. It also only prints 4 decimal digits for the fractional part, which isn't as precise as it could be.
For example, -3276.1 is represented as the int32_t
value -214702489 (-3276.1 * 65536 with the fractional part discarded). That has the same bit pattern as 0xF333E667. The display function determines the integer part to be printed by arithmetic shifting the value left by 16 bits, represented by the bit pattern 0xFFFFF333, and truncating to 16 bits, represented by the bit pattern 0xF333. As a signed integer, that bit pattern corresponds to -3277. The fractional part to be printed is determined by taking the low 16 bits, represented by the bit pattern 0xE667, corresponding to the decimal number 58983, multiplying by 10000, resulting in 589830000, and shifting right 16 bits (dividing by 65536), resulting in 9000. Therefore, the value is printed as -3277.9000.
Here is a function that displays the number properly, using 5 fractional digits:
void display32Q16 (int32_t num)
{
int32_t integer = num >> 16;
uint64_t fraction = num & 0xFFFF;
const char *xtrasign = "";
if (integer < 0 && fraction != 0)
{
integer++;
fraction = 65536 - fraction;
}
fraction = (fraction * 100000) >> 16;
if (num < 0 && integer == 0)
{
/* special case for number between -1 and 0 */
xtrasign = "-";
}
printf("Number = %s%" PRIi32 ".%05" PRIu64 "\n", xtrasign, integer, fraction);
}
Note that the original number resulting from -32761 / 10 will be displayed as -3276.09999 because the fractional part 0.1 cannot be represented exactly in binary.
It may be preferable to round to 4 decimal places as follows, and this also removes the need for 64 bit numbers.
void display32Q16 (int32_t num)
{
int32_t integer = num >> 16;
uint32_t fraction = num & 0xFFFF;
const char *xtrasign = "";
if (integer < 0 && fraction != 0)
{
integer++;
fraction = 65536 - fraction;
}
fraction = ((fraction * 10000) + (1 << 15)) >> 16;
if (fraction >= 10000)
{
/* deal with fraction rounding overflow */
if (num < 0)
integer--;
else
integer++;
fraction -= 10000;
}
if (num < 0 && integer == 0)
{
/* special case for number between -1 and 0 */
xtrasign = "-";
}
printf("Number = %s%" PRIi32 ".%04" PRIu32 "\n", xtrasign, integer, fraction);
}