CSCI 237

Computer Organization

Home | Schedule | Assignments | Links | Williams CS

Lab 1: Bit Manipulation in C

Assigned Feb 8, 2026
   
Prelim Due Date Tuesday, February 17 at 10:00pm. At least six functions in bits.c implemented and passing all tests (including proper number of operations).
   
Final Due Date Tuesday, February 24 at 10:00pm. All twelve functions in bits.c implemented.
   
Repository Info Individual starter code/submission available on GitLab

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), OS code, etc. By working your way through these problems, you will get very familiar with bit representations and hopefully have some fun.

How the Honor Code Applies to This Lab

This is an individual assignment. The programs written by students should represent their own work. Students are permitted to ask other students in the class questions of clarification, language syntax, and error message interpretation, but are not permitted to view/share each others' code or written design notes. Further, students should not use any resources beyond those directly provided by their instructor (no outside sources); in particular, viewing, searching, or querying descriptions of solutions to similar problems that you did not solve yourself is prohibited.

You may discuss the syntax and meanings of operations, data types, C language syntax, high-level understanding, and debugging with your classmates, but you should never discuss or look at any full or partial solution that is not your own.

Starter Code

To fetch the source files for this lab, clone your Lab 01 personal private repository found on evolene, which is our department's GitLab server. The directory on your local machine that you use to store the repository is up to you, but all of your work should be committed and pushed to your personal repository on evolene.

Note: Cloning your repository may require additional steps if you've never used a CS lab machine before. Specifically, you will likely want to set up your git configuration file (this is a one time thing that you will not need to do again).

         $ git config --global user.email "@williams.edu"
         $ git config --global user.name "Your Full Name"
         $ git config --global push.default simple
         $ git config --global pull.rebase false
         $ git config --global core.editor emacs

In order to use git on our unix machines you also need to copy a certificate into your home directory and tell git where to find it. This is not something you would do on your personal machines.

         $ git config --global http.sslCAInfo /home/cs-local-linux/certs/cacert.pem

These commands will create and update your `~/.gitconfig` file. This is a hidden file that keeps all the information git needs to know about your default setup. This hidden file is stored in your home directory and was created/updated by the `git config --global ...` commands you just ran.

Your repository 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 bitwise_and compute x&y using only ~ and |
1 set_third_bits returns a word (4 bytes) with every third bit set to 1
(Start counting from the right, e.g., ...1001001)
2 is_any_even_bit_set returns 1 if any even-numbered bit is set to 1
3 rotate_left rotate x to the left by n spaces
4 bitwise_parity returns 1 if x contains an odd number of 0's,
and 0 otherwise

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 is_tcomp_max returns 1 if x is the maximum two's complement number, and 0 otherwise
2 get_sign return 1 if positive, 0 if zero, and -1 if negative
2 negate return -x
3 is_sub_ok return 1 if x-y can be computed without overflow
4 is_pow_2 return 1 if x is a power of 2, and 0 otherwise

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_val return absolute value of f
4 float_div_2 return 0.5*f

Functions float_abs_val and float_div_2 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 NaNs, 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.

Additional Tools

ishow

The included program ishow helps you understand the structure of twos complement integers. To compile ishow, navigate to your repository and type:

         $ make

You can use ishow to see what an arbitrary bit pattern represents as a twos complement integer:

         $ ./ishow 0x27
         Hex = 0x00000027, Signed = 39, Unsigned = 39

or to see the bit representation of an arbitrary decimal value:

         $ ./ishow 27
         Hex = 0x0000001b, Signed = 27, Unsigned = 27

fshow

The included program fshow helps you understand the structure of floating point numbers. To compile fshow, navigate to your repository 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

Note: dlc will always output the following warning, which can be safely ignored:

         /usr/include/stdc-predef.h:1: Warning: Non-includable file <command-line>
         included from includable file /usr/include/stdc-predef.h.

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 bitwise_and

You can feed it specific function arguments using the option flags -1, -2, and -3:

         $ ./btest -f bitwise_and -1 7 -2 0xf

Check the file README.md 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 53 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 thoughtful. Thus, for each function we've established a maximum number of operators that you are allowed to use for that function. This limit is somewhat generous and is designed only to catch unnecessarily inefficient solutions. You will receive two points for each correct function that satisfies the operator limit.

Submitting Your Work

When you have completed the lab, commit and push your code to your gitlab repository using the appropriate git commands, such as:


          $ git status
          $ git add ...
          $ git commit -m "final submission"
          $ git push

Then, submit your code using submit237:


        $ submit237 1 bits.c

We will record the most recent submission that was sent using the submit237 script prior to the assignment deadline(s). However, it is still important to push your submission to gitlab.

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 gcc 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, you can use Google to 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
           gcc -O -Wall -m32 -g -lm -o btest bits.c btest.c decl.c tests.c
           gcc -O -Wall -m32 -g -o fshow fshow.c
           gcc -O -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 gcc. 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;
         }