Solutions will be posted on the Web by Friday, Feb. 26. Follow the links on the course Home Page.
Before continuing to describe the minifloat type, I need to introduce a bit of notation and some terminology. I will use the ** operator (borrowed from Fortran) for exponentiation; this is handy when writing mathematics in Web pages and program comments. (So, for example, 2**4 is 2 to the 4th power.)
I will use the terms hidden-MSB significand and full significand to distinguish between two related concepts. The distinction is most easily shown with an example: consider the number
1.1011 * two ** threewhere 1.1011 is a base two number. The full significand is 1.1011, and the hidden-MSB significand is 0.1011. The word significand in Section 4.8 of Patterson and Hennessy sometimes means hidden-MSB significand and sometimes means full significand; you have to pay careful attention to determine which meaning is in use in a particular sentence or formula.
The sign bit of a minifloat is 0 for positive numbers and 1 for negative numbers.
The exponent field of a minifloat is used as follows:
In a nonzero minifloat, the significand bits are used to represent the hidden-MSB significand. In representations of zero, the significand bits must all be 0.
Now that the uses of the individual fields have been described, it's possible to determine what real number (if any) is represented by an 8-bit pattern.
1.1011 * two ** threeNote that the 5-bit full significand is obtained by putting a 1 in front of the 4-bit MSB-hidden significand and that the exponent of three is obtained by subtracting the bias of three from the value of six (110). In base ten, the number is
(1 + 1/2 + 1/8 + 1/16) * 2 ** 3 = 1.6875 * 8 = 13.5
Let's consider the problem of determining a minifloat representation of a number given in base 10, say 0.390625. To start with we need to write our number in the form
sign * (full significand) * 2 ** exponentwhere the full significand is greater than or equal to 1 and less than 2. This gives us
0.390625 = 1 * 1.5625 * 2 ** (-2)The sign bit should be 0, obviously. The biased exponent should be -2 + 3, or 001 in base two. What is the MSB-hidden significand? Here I will cheat a little and just state that 0.5625 is in fact exactly 1/2 + 1/16, so the correct bit pattern is 1001. Putting all the bit fields together, the minifloat representation is 00011001.
The MSB-hidden significand in a minifloat is
bit3 / 2 + bit2 / 4 + bit1 / 8 + bit0 / 16From this it should be clear that the MSB-hidden significand is always an integer multiple of 1/16. Determining the significand bits in the previous example was relatively easy because 0.5625 just happened to be an integer multiple of 1/16. Most base ten fractions are not integer multiples of 1/16, so usually when converting from base ten to minifloat, the fractional part of the full significand will have to be rounded to an integer multiple of 1/16. The following table is useful for doing such rounding:
VALUE BASE TWO BASE TEN | VALUE BASE TWO BASE TEN 0/16 0.0000 0.0000 | 8/16 0.1000 0.5000 1/16 0.0001 0.0625 | 9/16 0.1001 0.5625 2/16 0.0010 0.1250 | 10/16 0.1010 0.6250 3/16 0.0011 0.1875 | 11/16 0.1011 0.6875 4/16 0.0100 0.2500 | 12/16 0.1100 0.7500 5/16 0.0101 0.3125 | 13/16 0.1101 0.8125 6/16 0.0110 0.3750 | 14/16 0.1110 0.8750 7/16 0.0111 0.4375 | 15/16 0.1111 0.9375Let's find a minifloat representation for -3.6, which is
-1 * 1.8 * 2**1The sign bit is 1 and the exponent field is 100. The significand bits depend on what rule we choose for rounding. If we use a round-to-nearest rule, the correct choice is 1101, because 0.8 is closer to 0.8125 than it is to 0.7500. With a round-towards-zero rule, the correct choice is 1100. Other rounding rules could be used instead, but in all cases the correct choice will be either 1100 or 1101 So the minifloat representation of -3.6 would be either 11001101 or 11001100; neither representation would be exact.
For each of the following minifloat bit patterns, determine the equivalent base ten number, or explain why no such base ten number can be found.
1. 00010010 2. 11010000 3. 10000000 5. 00001000 4. 00111111Convert each of the following base ten numbers to a minifloat representation, or explain why the conversion is not possible. If rounding is necessary, use round-to-nearest logic.
6. -13.1 7. 0.2 8. -0.1 9. 11.0 10. -18.5
On most present-day computers the C float type uses the 32-bit IEEE 754 representation. Since there are only 24 bits in the full significand of a 32-bit IEEE 754 number, most integers with magnitude greater than 2**24 can't be represented exactly in the float type. For example, if the following program:
is compiled and run on an x86-based Linux system, the output is#include <stdio.h> int main(void) { int i = 1234512345, j; float f; f = (float) i; j = (int) f; printf("i = %d, f = %f, j = %d.\n", i, f, j); return 0; }
The conversion on this system picks the nearest float to 1234512345, which is 1234512384.0. (The results are likely to be the same on any other system that has 32-bit ints and 32-bit IEEE 754 floats.) Picking the nearest float is a reasonable choice, but is not required by the C standard, which says that the result of an inexact int-to-float conversion must be one of two numbers: the smallest float larger than the int or the largest float smaller than the int.i = 1234512345, f = 1234512384.000000, j = 1234512384.
Study the code and comments in int2float.spim. Make a printout and trace the program instruction by instruction, using a pen or pencil to keep track of the contents of registers used in the procedure int2float. What are the contents of $a0, $t0, and $t1 at point one? What is $v0 at point two? Make a serious effort to get correct answers without running the program; this will take some time but it should teach you quite a bit about manipulating bit patterns with logic instructions such as sll, srl, and, and or.
Use xspim to run the program. If you set a breakpoint or two in appropriate places you can very quickly check the values you found when tracing the program by hand.
Suppose you are asked to find the product of two minifloats, and the only tools you have are a pencil and some paper.
Here is an algorithm that works on positive minifloats only, illustrated with an example. Let's suppose you are asked to multiply 01101011 and 00101101.
On processors without a floating-point unit, a sequence of integer instructions is needed to multiply two 32-bit floating-point numbers. You can learn a lot about floating-point arithmetic by attempting to multiply floating-point numbers with integer instructions.
Run the program floatmul.spim to see what it does.
Add code to the floatmul procedure so that it does the job described in the comments near the top of the procedure. In order to keep this exercise relatively simple, you may make the following assumptions:
This is a relatively challenging exercise. Make a serious effort to get your code working, but recognize that the main goal is to learn about floating-point number representations and manipulation of bit fields. (In other words, don't burn twelve hours trying to debug code that almost works!)