CSCI 237
Computer Organization
Home | Lectures | Labs | CS@Williams
Lab 1: Manipulating Bits Using C
Assigned | Feb 12/13, 2025 |
---|---|
Prelim Due Date | Feb 18/19 at 11:00pm. At least six functions in bits.c implemented and passing all tests (including proper number of operations). |
Final Due Date | Feb 25/26 at 11:00pm. All twelve functions in bits.c implemented. |
Files | lab1.tar
[Slides]
|
Submissions | Submit your completed bits.c using submit237. |
Overview
The purpose of this assignment is to become more familiar with data at the bit-level representation. You will 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 and hopefully have some fun.
Instructions
This is an individual assignment. You may discuss operations, high level understanding, and debugging with your classmates, but you should not discuss the solutions.
To fetch the source files for this lab, right click on lab1.tar
and choose "Save As" to download the
tarball to your local directory. You may want to move this file to a more desirable
location using the Unix mv
command. Alternatively, if you are using
SSH
to work remotely, you may want to use wget
to fetch
the file. Once you have used cd
to navigate to the desired directory,
you can use the following command to fetch the tarball:
$ wget http://dept.cs.williams.edu/~jeannie/cs237/labs/lab1/lab1.tar
Extract the contents using the following command:
$ tar xf lab1.tar
tar
is a file archive utility; the "xf" options mean to
extract the file give as an argument. This
should generate a directory next to lab1.tar called lab1 that contains a number
of tools, described later, and a bits.c file. This file
contains skeletons for the programming puzzles, along with a comment block that
describes exactly what the function must do and what restrictions there are on
its implementation. Your assignment is to complete each function skeleton
using:
The intent of the restrictions is to require you to think about the data as bits -- because of the restrictions, your solutions won't be the most efficient way to accomplish the function's goal, but the process of working out the solutions should make the notion of data as bits completely clear.
The Bit Puzzles
This section describes the puzzles that you will be solving in bits.c. More complete (and definitive, should there be any inconsistencies) 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 | bitNor | ~(x | y) using only ~ and & (Hint: DeMorgan's Law) |
1 | evenBits | return word (4 bytes) with all even-numbered bits set to 1
(Start counting from the left, e.g., 0101...) |
2 | allOddBits | return 1 if all odd-numbered bits in word are set to 1
(Again, start counting from the left, e.g., 1010... should return 1) |
3 | rotateLeft | rotate x to the right by n spaces |
4 | bitParity | return 1 if x contains an odd number of 0's |
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 |
---|---|---|
1 | isTmin | returns 1 if x is the minimum, two's complement number |
2 | fitsBits | return 1 if x can be represented as an n-bit, two's complement integer (Hint: -1 = ~0) |
2 | isNotEqual | return 0 if x == y, and 1 otherwise |
3 | subOK | return 1 if x-y can be computed without overflow |
4 | isNonZero | return 1 if x is nonzero, cannot use ! |
Floating-Point Operations
For this part of the assignment, you will implement
some common single-precision floating-point operations. In this
section, you are allowed to use standard control structures
(conditionals, loops), and you may use both int
and unsigned
data types, including arbitrary unsigned and integer constants. You may
not use any unions, structs, or arrays. Most significantly, you may
not use any floating point data types, operations, or constants.
Instead, any floating-point operand will be passed to the function as
having type unsigned
, and any returned floating-point value will be
of type unsigned
. Your code should perform the bit manipulations that
implement the specified floating point operations.
The following table describes a set of functions that operate on the bit-level representations of floating-point numbers. Refer to the comments in bits.c and the reference versions in tests.c for more information.
Rating | Function Name | Description |
---|---|---|
2 | float_abs | return abs value of f |
4 | float_half | return 0.5*f |
Functions float_abs
and float_half
must
handle the full range of possible argument values, including not-a-number (NaN) and
infinity. The IEEE standard does not specify precisely how to handle NaN's, and
the IA32 behavior is a bit obscure. We will follow a convention that for any function returning
a NaN value, it will return the one with bit representation 0x7FC00000
.
The included program fshow
helps you understand the
structure of floating point numbers. To compile fshow
, switch to the
handout directory and type:
$ make
You can use fshow
to see what an arbitrary pattern
represents as a floating-point number:
$ ./fshow 2080374784 Floating point value 2.658455992e+36 Bit Representation 0x7c000000, sign = 0, exponent = f8, fraction = 000000 Normalized. 1.0000000000 X 2^(121)
You can also give fshow
hexadecimal and floating point values, and
it will decipher their bit structure.
Checking Your Work
We have included two tools to help you check the correctness of your work.
dlc
is a modified version of an ANSI C compiler from
the MIT CILK group 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
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 bitNor
You can feed it specific function arguments using the option
flags -1
, -2
, and -3
:
$ ./btest -f bitNor -1 7 -2 0xf
Check the file README 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.
Evaluation
Your score will be computed out of a maximum of 55 points based on the following distribution:
Correctness points. The 12 puzzles you must solve have been given a difficulty rating between 1 and 4, such that their weighted sum totals to 29. We will evaluate your functions using the btest program, which is described above. You will get full credit for a puzzle if it passes all of the tests performed by btest, and no credit otherwise.
Performance points. Our main concern at this point in the course is that you can get the right answer. However, we want to instill in you a sense of keeping things as short and simple as you can. Furthermore, some of the puzzles can be solved by brute force, but we want you to be more clever. Thus, for each function we've established a maximum number of operators that you are allowed to use for each function. This limit is very generous and is designed only to catch egregiously inefficient solutions. You will receive two points for each correct function that satisfies the operator limit.
Style points. Finally, we've reserved 2 points for a subjective evaluation of the style of your solutions and your commenting. Your solutions should be as clean and straightforward as possible. Your comments should be informative, but they need not be extensive.
When you have completed the lab, submit your code using submit237:
$ submit237 1 bits.c
Advice
Start early on bits.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. Google may be used to help with basic understanding of operators, but you should not Google for solutions. If you do not quite meet the operator limit, don't worry! There will be partial credit for suboptimal solutions, but often times working with a suboptimal solution will allow you to see how to improve it.
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 the compiler will print a warning that you can
ignore.
You should be able to use the debugger on your code. If you are unfamiliar with gdb, Google can help (as well as your TAs or your instructor). This GDB info page from Harvey Mudd and this GDB quick reference from the Univ of Texas are also very helpful. Sample usage:
$ make
clang -O0 -Wall -m32 -g -lm -o btest bits.c btest.c decl.c tests.c
clang -O0 -Wall -m32 -g -o fshow fshow.c
clang -O0 -Wall -m32 -g -o ishow ishow.c
$ gdb ./btest
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./btest...done.
(gdb) b bitNor
Breakpoint 1 at 0x80487bb: file bits.c, line 173.
(gdb) r
Starting program: /home/faculty/jeannie/cs237/datalab/datalab-handout/btest
ScoreRatingErrorsFunction
Breakpoint 1, bitNor (x=-2147483648, y=-2147483648) at bits.c:173
173}
(gdb) p x
$1 = -2147483648
(gdb) p/x x
$2 = 0x80000000
(gdb) q
A debugging session is active.
Inferior 1 [process 16084] will be killed.
Quit anyway? (y or n) y
The dlc
program enforces a stricter form of C
declarations than is the case for C++ or that is enforced
by the compiler. 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;
}
Beat the Prof
For fun, we're offering a completely optional "Beat the Prof" contest that allows you to compete with other students and the instructor to develop the most efficient puzzles. The goal is to solve each puzzle using the fewest number of operators. Students who match or beat the instructor's operator count for each puzzle are winners! (Sadly, no real prizes will be awarded, but you'll earn lots of bragging rights!)
To submit your entry to the contest, type:
$ ./driver.pl -u "Your Nickname"
Nicknames are limited to 35 characters and can contain alphanumerics, apostrophes, commas, periods, dashes, underscores, and ampersands. You can submit as often as you like. Your most recent submission will appear on a real-time scoreboard, identified only by your nickname. You can view the scoreboard by pointing your browser at http://sysnet.cs.williams.edu:8080.