4 Using Fractional Numbers

Unsigned 8-bit fractional numbers use a format where numbers in the range [0, 2> are allowed. Bits 6 - 0 represent the fraction and bit 7 represents the integer part (0 or 1), i.e., a 1.7 format. The FMUL instruction performs the same operation as the MUL instruction, except that the result is left-shifted 1-bit so that the high byte of the 2-byte result will have the same 1.7 format as the operands (instead of a 2.6 format). Note that if the product is equal to or higher than 2, the result will not be correct.

To fully understand the format of the fractional numbers, a comparison with the integer number format is useful: The table below illustrates the two 8-bit unsigned numbers formats. Signed fractional numbers, like signed integers, use the familiar two’s complement format. Numbers in the range [-1, 1> may be represented using this format.

If the byte “1011 0010” is interpreted as an unsigned integer, it will be interpreted as 128 + 32 + 16 + 2 = 178. On the other hand, if it is interpreted as an unsigned fractional number, it will be interpreted as 1 + 0.25 + 0.125 + 0.015625 = 1.390625. If the byte is assumed to be a signed number, it will be interpreted as 178 - 256 = -122 (integer) or as 1.390625 - 2 = -0.609375 (fractional number).
Table 4-1. Comparison of Integer and Fractional Formats
Bit number7654
Unsigned integer bit significance27=12826=6425=3224=16
Unsigned fractional number bit significance20=12-1=0.52-2=0.252-3=0.125
Bit number321|
Unsigned integer bit significance23=822=421=220=1
Unsigned fractional number bit significance2-4=0.06252-5=0.031252-6=0.0156252-7=0.0078125

Using the FMUL, FMULS, and FMULSU instructions should not be more complex than the MUL, MULS, and MULSU instructions. However, one potential problem is to assign fractional variables right values in a simple way. The fraction 0.75 (= 0.5 + 0.25) will, for example, be “0110 0000” if eight bits are used.

To convert a positive fractional number in the range [0, 2> (for example 1.8125) to the format used in the AVR, the following algorithm, illustrated by an example, should be used:

Is there a “1” in the number?

Yes, 1.8125 is higher than or equal to 1. Byte is now “1xxx xxxx”

Is there a “0.5” in the rest?

0.8125/0.5 = 1.625

Yes, 1.625 is higher than or equal to 1.

Byte is now “11xx xxxx”

Is there a “0.25” in the rest?

0.625/0.5 = 1.25

Yes, 1.25 is higher than or equal to 1.

Byte is now “111x xxxx”

Is there a “0.125” in the rest?

0.25/0.5 = 0.5

No, 0.5 is lower than 1.

Byte is now “1110 xxxx”

Is there a “0.0625” in the rest?

0.5/0.5 = 1

Yes, 1 is higher than or equal to 1.

Byte is now “1110 1xxx”

Since we do not have a rest, the remaining three bits will be zero, and the final result is “1110 1000”, which is 1 + 0.5 + 0.25 + 0.0625 = 1.8125.

To convert a negative fractional number, first add two to the number and then use the same algorithm as already shown.

16-bit fractional numbers use a format similar to that of 8-bit fractional numbers; the high eight bits have the same format as the 8-bit format. The low eight bits are only an increase of accuracy of the 8-bit format; while the 8-bit format has an accuracy of ±2-8, the16-bit format has an accuracy of ±2-16. Then again, the 32-bit fractional numbers are an increase of accuracy to the 16-bit fractional numbers. Note the important difference between integers and fractional numbers when extra byte(s) are used to store the number: while the accuracy of the numbers is increased when fractional numbers are used, the range of numbers that may be represented is extended when integers are used.

As mentioned earlier, using signed fractional numbers in the range [-1, 1> has one main advantage to integers: when multiplying two numbers in the range [-1, 1>, the result will be in the range [-1, 1], and an approximation (the highest byte(s)) of the result may be stored in the same number of bytes as the factors, with one exception: when both factors are -1, the product should be 1, but since the number 1 cannot be represented using this number format, the FMULS instruction will instead place the number -1 in R1:R0. The user should therefore assure that at least one of the operands is not -1 when using the FMULS instruction. The 16-bit x 16-bit fractional multiply also has this restriction.