CSCI 237

Computer Organization

Home | Lectures | Labs | CS@Williams

Lab 1: Manipulating Bits Using C

Assigned Feb 7/8, 2024
Prelim Due Date Feb 13/14 at 11:59pm. At least six functions in bits.c implemented and passing all tests (including proper number of operations).
Final Due Date Feb 20/21 at 11:59pm. 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.