![]() |
CSCI 2330 Spring 2017 Instructor: Sean Barker |
![]() |
This project should be completed individually.
This project is designed to make you more familiar with the bit-level representations of data used by computers. At the same time, you will become well-acquainted with the bitwise manipulations available in many languages (like C). You will do this by solving a series of (fun, enlightening, and challenging!) programming puzzles in C.
Start by reading through the entire project description, particularly the advice section!
Assigned | Sunday, February 5. |
Checkpoint 1 | Friday, February 10. At least three puzzles must be completed by this checkpoint (including documentation). |
Checkpoint 2 | Wednesday, February 15. At least nine puzzles must be completed by this checkpoint (including documentation). |
Due | Monday, February 20. All fifteen puzzles are due by this date. |
In this project, you will modify a single C source file, puzzles.c, which is included in the starter files. This file contains the skeleton for a set of 15 programming puzzles. Each puzzle is a function which should compute a simple operation (e.g., returning whether a given number is positive or negative). Your task is to complete each function using a highly restricted subset of the full C language. In particular:
Exception: For floating-point puzzles, you do not need to adhere to the restrictions on branching, looping, constants, or operators, and you may use both int and unsigned types (but no floating-point types). Other restrictions still apply (e.g., no function calls).
In order to solve the puzzles while following the rules above, you will need to have a clear understanding of data representations and be clever about using bitwise operators!
Puzzles may make use of either raw bitwise values (i.e., bits not interpreted as numbers), integers, or floating-point numbers. Integers use a 2's complement representation and floating point numbers use the standard IEEE floating point representation discussed in class.
Each puzzle is assigned a difficulty rating from 1 to 4 reflecting my subjective rating of the complexity of that puzzle (1 = easiest, 4 = hardest). Puzzles with the lowest rating may be straightforward given a few minutes of thought. Harder puzzles will almost certainly require a non-trivial amount of thought, experimentation, and possibly pen-and-paper exploration. Don't underestimate how long the later puzzles will take based on the earlier puzzles!
In addition to your code implementing each puzzle, you must provide explanations (via comments embedded in puzzles.c) of how and why each of your solutions works. Your comments must go beyond a simple translation of the bitwise operations you used. Rather, your comments must clearly demonstrate that you understand why (as opposed to simply how) your solution works. For example, a comment that says "shifts the bits right by 3 and then AND's by 1" simply restates the binary operations themselves and does not provide any real information. A better comment might be "extracts the fourth-lowest bit of the number by shifting right 3 and then ANDing by 1".
In some cases, your comments may end up exceeding the length of your code (though this is not strictly a requirement). Do not neglect your explanations, as they will factor significantly into your project grade.
Complete reference implementations of the puzzles are provided in tests.c that make use of the entire C language. Refer to these if you have any question about how a given function is supposed to behave. However, given that these implementations do not have any restrictions, they are not likely to be especially helpful in how to actually approach your functions.
Checking your puzzle solutions can be tricky. Luckily, you will have a couple of useful tools at your disposal.
The ishow utility accepts an integer input (either in decimal or hex format) and outputs its signed, unsigned, and raw-bit (in hex) equivalents. For example:
$ ./ishow 20 Hex = 0x00000014, Signed = 20, Unsigned = 20 $ ./ishow 0xffffffff Hex = 0xffffffff, Signed = -1, Unsigned = 4294967295
The fshow utility accepts either an integer or hex value representing an arbitrary bit pattern, or a float-point number, and outputs the corresponding floating point value and representation components. For example:
$ ./fshow 5.25 Floating point value 5.25 Bit Representation 0x40a80000, sign = 0, exponent = 0x81, fraction = 0x280000 Normalized. +1.3125000000 X 2^(2) $ ./fshow 100 Floating point value 1.401298464e-43 Bit Representation 0x00000064, sign = 0, exponent = 0x00, fraction = 0x000064 Denormalized. +0.0000119209 X 2^(-126)
The blc (bit lab compiler) utility is a modified C compiler that will check your solutions for compliance with the coding rules specified. To check the compliance (but not correctness) of your solutions, run blc on your puzzles.c file as follows:
$ ./blc puzzles.c
If your program is fully compliant, no output will be produced (otherwise, an error message will be printed). You can also count the number of operations in each function by passing the -e switch:
$ ./blc -e puzzles.c
To check the correctness (but not compliance) of your solutions, use the btest utility. To use btest, you must compile it using the included Makefile by typing make, which will compile it using your current puzzles.c file. This means that your must rebuild btest each time you modify puzzles.c. You should not modify the included Makefile.
Once compiled, simply run the utility directly to check the correctness of all your solutions:
$ ./btest
You can also use the -f flag to tell btest to test only a single named function, like this (assuming a function named foo):
$ ./btest -f foo
While btest normally checks your solutions against many possible inputs, you can also check specific inputs using the flags -1, -2, and -3. For example, to test the correctness of foo(5, 0xF), you could run the following:
$ ./btest -f foo -1 5 -2 0xF
The driver.pl utility (a Perl script, if you are curious) will both run btest to check your solutions as well as count the number of operations used. To use it, simply execute it directly:
$ ./driver.pl
The script will output an autogenerated score for each puzzle out of 1-4 possible correctness points (based on the difficulty rating of the puzzle) and 2 possible performance points (based on the number of operations used). The total score shown does not correspond directly to your project score (in particular, a full performance score is not necessary for full credit) but will give you a sense of where improvement is possible.
Non-includable file <command-line> included from includable file /usr/include/stdc-predef.h.
int foo(int x) { int a = x; a *= 2; // not a declaration int b = a; // ERROR: can't put a declaration after a non-declaration }To fix the above code, you would need to break the int b = a; line into separate declaration and assignment lines, and put the declaration before the a *= 2; line.
The project files have been added to your SVN directory for you -- to download them, simply do an update in your checked-out SVN directory. The *only* file you need to modify is puzzles.c.
Remember that you need to do your work on turing, not on your local machine -- since the files are compiled for Linux, they will not execute on a Mac or a Windows PC.
Your committed puzzles.c at the project due date (and each of the intermediate checkpoints) will constitute your project submission. Remember that if you haven't committed your work, it's not submitted (but you should be committing frequently as you work in any case)!
You will be evaluated on the contents of your puzzles.c file, which must contain both your puzzle solutions and your solution explanations. Do not store any work that you would like to be considered outside this file!
Your project will be evaluated as follows:
Partial credit is possible for puzzle solutions that are not complete, provided some understanding of the problem is apparent (note that good documentation will be doubly important here).
Just for fun, as part of this project, you may participate in a completely optional contest to compete against other students and my solution to develop the most efficient puzzle solutions. The goal of the contest is to solve each puzzle using the fewest number of operators. Students who match or beat my solution's operator count for each puzzle are winners (prizes include the "Bit Hacker" designation and bragging rights!)
To submit your puzzle entries to the contest, simply call the driver with a -u flag providing a nickname that you would like to show on the scoreboard:
$ ./driver.pl -u "Your Nickname"
You may use any nickname you like and it need not identify yourself to other contest entrants (though I will be able to see your entries regardless of your nickname). You can submit to the contest as often as you like and there is never any penalty for doing so.
Your most recent contest submission will appear on a real-time scoreboard, identified only by your nickname. Follow the below link to view the current scoreboard.