Bit Transfiguration
- Checkpoint: complete at least 5 puzzles by 11:00pm Tuesday, 15 September
- Due: 11:00pm Thursday 17 September
- Starter code: fork wellesleycs240 / cs240-bits (just once!) and add bpw as admin. (Need help?)
- Submissions:
- Commit and push your final version. (Need help?)
- Do not submit a paper copy.
- Relevant reading, as needed:
- CSAPP 2.1.7 - 2.1.10, 2.2 - 2.3
- K&R 2.7, 2.9
- Collaboration: This assignment follows the standard collaboration policy. You may discuss problems and high-level strategies with other students, but your solutions must be your own work. You must cite anyone with whom you discussed the problems in a comment at the top of the
bits.c
file.
Complete this assignment using one of the GNU/Linux environments supported for this course or meet certain doom. (More or less.) For example, we have seen solutions that fail with the Mac’s C compiler work with GCC on Linux. The reverse is likely possible too.
Before starting to write code for this assignment, get familiar with the CS 240 tools if you did not get a chance during lab. You will use these tools repeatedly during this assignment and the rest of the course.
Contents
Overview
The purpose of this assignment is to become more familiar with data representation at the bit level. You’ll do this by solving a series of programming “puzzles.” Many of these puzzles may seem artificial, but in fact bit manipulations are very useful in cryptography, data encoding, implementing file formats (e.g., MP3), etc. By working your way through these problems, you will get very familiar with bit representations. Hopefully you will have some fun along the way!
The short Integer Arithmancy exercises will help familiarize you with number representations for this assignment.
Instructions
Get the source files for this assignment from the wellesleycs240 / cs240-bits repository, following the same fork-share-clone process described here, as we did in the first lab meeting, but replacing the cs240-lab1 repository with cs240-bits.
Your working copy should contain a number
of tools, described later, and a bits.c
file
containing skeletons for the programming puzzles, along with comment blocks that
describe exactly what the functions must do and what restrictions there are on
implementation. Your assignment is to complete each function skeleton
using:
- only straightline code (i.e., no loops or conditionals);
- a limited number of C arithmetic and logical operators; and
- no constants larger than 8 bits (i.e., 0 - 255 inclusive).
Carefully read the coding rules found in the bits.c
file.
The intent of the restrictions is to require you to think about the data as bits – because of the restrictions, your solutions may not be the simplest or most efficient way to accomplish the function’s goal, but the process of working out the solution should make the notion of data as bits completely clear.
Please skim the entire document before starting to work.
Bit Puzzles
This section describes the puzzles that you will be solving in
bits.c
. More complete documentation is found in the bits.c
file itself.
Bit Manipulations
The table below describes a set of functions that manipulate and test sets of bits. The Rating column gives the difficulty rating (the number of points) for each puzzle and the Description column states the desired output for each puzzle along with the constraints. See the comments in bits.c for more details on the desired behavior of the functions. You may also refer to the test functions in tests.c. These are used as reference functions to express the correct behavior of your functions, although they don’t satisfy the coding rules for your functions.
Rating | Function Name | Description |
---|---|---|
1 | bitAnd | x & y using only ~ and | |
1 | bitXor | x ^ y using only ~ and & |
1 | thirdBits | return word with every third bit (starting from the LSB) set to 1 |
2 | getByte | Extract byte n from word x |
3 | logicalShift | shift x to the right by n, using a logical shift |
4 | bang | Compute !x without using ! |
3 | Optional: conditional |
x ? y : z |
Two’s Complement Arithmetic
The following table describes a set of functions that make use of
the two’s complement representation of integers. Again, refer to the
comments in bits.c
and the reference versions in tests.c
for more
information.
Rating | Function Name | Description |
---|---|---|
2 | fitsBits | returns 1 if x can be represented as an n-bit, two's complement integer |
2 | sign | return 1 if positive, 0 if zero, and -1 if negative |
3 | addOK | Determine if x+y can be computed without overflow |
4 | Optional: isPower2 |
returns 1 if x is a power of 2, and 0 otherwise |
Checking Your Work
We have included a few tools to help you check your work.
dlc
: Compliance
dlc
is a modified C compiler that you can use to check for compliance with the coding rules for each puzzle. The typical usage is:
$ ./dlc bits.c
The program runs silently unless it detects a problem, such as an
illegal operator, too many operators, or non-straightline code in the
integer puzzles. Running with the -e
switch:
$ ./dlc -e bits.c
causes dlc
to print counts of the number of operators
used by each function. Type ./dlc -help
for a list of
command line options.
btest
: Testing
btest
is a program that checks the functional
correctness of the code in bits.c
. To build and use it, type the
following two commands:
$ make
$ ./btest
Notice that you must rebuild btest
each time you
modify your bits.c
file. (You rebuild it by typing make
.)
You’ll find it helpful to work through the functions one at a time,
testing each one as you go. You can use the -f
flag to
instruct btest
to test only a single function:
$ ./btest -f bitXor
You can feed it specific function arguments using the option
flags -1
, -2
, and -3
:
$ ./btest -f bitXor -1 7 -2 0xf
Check the README
file for documentation on running the btest
program.
We may test your solution on inputs that btest does not check by default and we will check to see if your solutions follow the coding rules.
driver.pl
: Combined Testing and Conciseness
The driver.pl
tool will both run btest
and count the number of operators your solutions, displaying an automatically generated score for each. Here is (part of) the output on our sample solution:
$ ./driver.pl
[ ... status messages omitted here ... ]
Correctness Results Perf Results
Points Rating Errors Points Ops Puzzle
1 1 0 2 4 bitAnd
1 1 0 2 7 bitXor
1 1 0 2 4 thirdBits
2 2 0 2 7 fitsBits
2 2 0 2 4 sign
2 2 0 2 3 getByte
3 3 0 2 14 logicalShift
3 3 0 2 9 addOK
4 4 0 2 6 bang
3 3 0 2 7 conditional
4 4 0 2 11 isPower2
Score = 48/48 [26/26 Corr + 22/22 Perf] (76 total operators)
The “performance” score is based on the number of operators used. Fewer operators = higher score, in a range of 0-2 for each puzzle, but getting the absolute minimum number of operators is not necessary to get the full score. The combined score is not a direct indicator of your grade, but it is useful in estimating how close your solutions are to being correct and optimal. (Remember, it does not test all cases, so there may be others where your code is incorrect. It pays to think about edge cases and run extra tests manually!)
Grading
Your base grade will be derived as follows:
- 70% correctness
- 15% low operator count
- 15% succint and clear comments describing why your implementations work
Comments should demonstrate clearly to the course staff that you understand the series of operations you apply and how and why they work to accomplish the goal. In some cases your comments may be shorter than your code. In some cases they may be longer.
Partial credit may be awarded for partially working solutions or comments describing an intended approach that you did not finish implementing.
Advice
Start early. Try some pencil-and-paper or whiteboard hacking to design your solution before you start typing C.
If you get stuck on one problem, move on. You may find you suddenly realize the solution the next day. Puzzle over the problems yourself, it is much more rewarding to find the solution yourself than stumble upon someone else’s solution. If you do not quite meet the operator limit don’t worry there will be partial credit, but often times working with a suboptimal solution will allow you to see how to improve it.
Commit often. Each time you get a new function working (or even just closer to working), commit your work. Also push your commits to your Bitbucket repository reasonably often. Then if things go wrong later you can always recover your work.
Number Conversion
The ishow
tool lets you display integer representations and conversions. It takes hex or decimal input.
$ ./ishow 0x27
Hex = 0x00000027, Signed = 39, Unsigned = 39
Debugging
Do not include the stdio.h
header file in your
bits.c
file, as it confuses dlc and results in some non-intuitive
error messages. You will still be able to use printf in your bits.c
file for debugging without including the stdio.h
header, although gcc
will print a warning that you can
ignore.
Variable Declarations
The dlc
program enforces a stricter form of C
declarations than gcc
enforces. In particular, in a block (what you enclose in
curly braces) all your variable declarations must appear before any
statement that is not a declaration. For example, dlc
will complain about the following code:
int foo(int x) {
int a = x;
a *= 3; /* Statement that is not a declaration */
int b = a; /* ERROR: Declaration not allowed here */
}
Instead, you must declare all your variables first, like this:
int foo(int x) {
int a = x;
int b;
a *= 3;
b = a;
}