Assignment: Bits

Contents

Overview1

This assignment requires you to solve a series of programming puzzles using only bitwise operations. Some puzzles may seem far removed from your previous programming experience, but bit manipulations like these are crucial for efficiency in essential applications such as cryptography, data compression, or encoding and decoding pictures, audio, video, and more. The puzzles will push you to think in new ways and internalize how computers deal with bit representations. Mind-twisters, enlightenment, and fun await!

Goals

  • To understand the representation and manipulation of data as bits.
  • To communicate how low-level bitwise operations relate to high-level data operations through representation.
  • To master unsigned and two’s complement number representation.
  • To become comfortable with basics of the C programming language.
  • To practice using command-line tools for programming.
  • To have at least one mind-blowing realization about two’s complement.

Advice

This is your first 240 code assignment. It is more challenging (and fun!) than the paper exercises that precede it. Here is some advice:

  • Complete Assignment Zero before starting. Knowing your way around the tools will pay off now, all semester, and beyond.

  • Start early. This assignment takes considerably longer than the earlier paper exercises. Allow time to work, get stuck, sleep on it, and come back repeatedly. Any recent CS 240 alum will confirm that we are serious about starting early!

  • Prepare and plan before you code. Complete the preparatory exercises. Try some pencil-and-paper or whiteboard hacking to design your solution before you start typing C.

  • Commit and push often. Each time you get a new function working (or even just closer to working), git add and git commit your work. Also git push your commits reasonably often. If things go wrong later you can always recover your work.

Time Reports

In a past semester, according to self-reported times for a similar version of this assignment:

  • 25% of students spent <= 7 hours.
  • 50% of students spent <= 9 hours.
  • 75% of students spent <= 12 hours.

Setup

Complete Assignment Zero to learn the standard CS 240 tools before starting this assignment.

CS 240 code assignments require a CS 240 GNU/Linux computing environment.

CS 240 code assignments are designed, tested, and graded in the CS 240 GNU/Linux computing environment, since low-level system details matter in this course. We guarantee support (help with provided tools) and consistency (our grading and your testing use the same environment) only for work in a CS 240 GNU/Linux computing environment.

Get the Code

Each student is provided with a bits repository hosted on the CS 240 repository server. This repository contains starter code and is where you will submit your work for the assignment.

This assignment can be completed either alone or with a partner, but it is strongly recommended that you work with a partner. Please see the specific directions below for each possibility.

Working Alone

To start, run cs240 start bits --solo to create your hosted repository and clone it to your CS account.

Working with a Partner

To start, one team member should run cs240 start bits to create your hosted repository and clone it to your CS account. You will be prompted to enter your teammate’s user ID. The user ID comes from the first part of your email address. For instance, adavis15 in adavis15@wellesley.edu.

It is strongly recommended that you work together on the same computer using just one cloned repository. This ensures that partners are brainstorming, testing, communicating, and solving these puzzles together. However, sometimes it is helpful for teammates to work separately and then come together later to discuss. For the partner who did run the above setup, that person can also get a cloned copy of the same repository. Simply run cs240 start bits. Make sure to enter the same team that you did before to ensure you get the same hosted repository.

  • Important: You may have created a bits repository in lab that was either a solo repository or a repository with a different partner. This is okay. Simply give the old repository a different name using the mv command. For instance, mv bits bits_lab. Note this command assumes you are in the same directory as your bits repository. Then simply run the steps above using your new teammate.
  • The Team Workflow summary or the full Git and CodeTub tutorial describe this process in more detail.

Code Overview

Your repository initially contains many files. The only file that you need to inspect or edit is:

  • bits.c: file where you will implement bit puzzle solutions

The other files support for testing. You do not need to inspect them, though you are free to do so. You will be compiling or running them along with your code in bits.c. The most important ones are:

  • btest.c, ‘extest.c, dlc, driver.pl`: testing code and tools
  • Makefile: recipes to compile testing code with the make command

Tasks

Your task is to solve the given bit puzzles and explain your solutions. The bits.c file contains rules, specifications, and function templates for the programming puzzles. For each puzzle, you must:

  • Implement the function according to the specification and coding rules that are specified in the function header comments for that function.
  • Explain in one or more comments how and why your solution works.

    Translating the operations into English or re-explaining the high-level specification do not suffice. You must demonstrate that you understand the link between the high-level behavior and its low-level implementation. How/why do the effects of the individual operations combine to implement the specification?

Grading considers correctness and compliance of your implementations as well as effectiveness of your explanations.

The remainder of this document describes:

  1. Preparatory exercises to help you review and start the assignment.
  2. Specifications and rules for the puzzle functions you must implement.
  3. Documentation of how to compile and test your implementation.
  4. Grading criteria.

Preparatory Exercises

CS 240 code assignments include preparatory exercises. Preparatory exercises are required, but not graded (unless otherwise noted).

Preparation is your ticket for assistance.

A. Get the code (and know your tools).

Complete the setup steps above to refresh your memory of the course software tools and acquire assignment code.

B. Read the instructions.

As you read this document and the coding rules given in bits.c, complete these exercises to familiarize yourself with the coding restrictions, the compilation process, and puzzle functions.

  1. What command should you run to compile your code?
  2. What command should you run to test both correctness and compliance of your solutions?
  3. Where are loops allowed?
  4. How many arguments does the thirdBits function take? What operators are allowed in thirdBits?

C. Practice bitwise thinking.

  1. Review the zero.c functions from Assignment Zero.

  2. Complete and review the class Exercises from Data as Bits.
  3. Before trying the Two’s Complement Functions, complete and review the Exercises from Integer Representation.

  4. Recommended: Try some practice problems from CSAPP: 2.8, 2.9, 2.14, 2.16

Puzzle Specifications

General Restrictions

All puzzle function implementations must obey the restrictive coding rules at the top of bits.c. Read the rules carefully before starting – they are essential. The rules restrict you to performing only bit-level operations on data. The purpose of these restrictions is to force you to think about the data as bits. Due to 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.

Individual Specifications

For each individual function:

  • A function header comment in bits.c gives:
    • a specification of the function’s behavior
    • some examples of the input/ouput behavior of the function. These examples are coded as test cases in extest.c.
    • the set of operators allowed (a specific subset of the operators ~ & | ^ + << >> !)
    • the maximum number of operations allowed
    • a rough difficulty rating, from low (1) to high (4)2
  • A testing harness in tests.c gives alternative documentation of expected behavior in terms of a reference implementation of the function

Tables below summarize the difficulty rating and description of each function.

Raw Bitwise Functions

These functions do checks and manipulations on 32-bit int values treated as bit vectors (i.e., they do not interpret the values as numbers).

Rating Function Short Description
1 bitAnd x & y using only ~ and |
1 [Independent] bitXor x ^ y using only ~ and &
1 thirdBits Return the int value where every third bit (including the LSB) is 1
2 getByte Extract byte n from word x
3 logicalShift Logical shift x to the right by n
4 [Independent] bang Compute !x without using !
3 conditional x ? y : z

Two’s Complement Functions

These functions do checks and manipulations of 32-bit 2’s-complement int values.

Rating Function Short Description
2 fitsBits Return 1 if x can be represented as an n-bit, two's complement integer
2 [Independent] sign Return 1 if positive, 0 if zero, and -1 if negative
3 addOK Determine if x+y can be computed without overflow
4 [Provided Sample] isPower2 Return 1 if x is a power of 2, and 0 otherwise

Compiling and Testing

There are 4 key steps for checking your work:

  1. Use make to compile your code and generate the btest.bin executable.
  2. Use btest.bin to check your solution’s functional correctness.
  3. Use dlc to check your solution’s compliance with the coding rules.
  4. Use driver.pl to autograde your solution.

The dlc and driver.pl tools enforce strict coding rules and will raise error messages if you have use prohibited or unsupported code. See Common Issues if you are confused by error messages in these steps.

Compiling: make

To build (compile) your solutions and provided testing code, type the command make.

$ make

The make command looks for a file called Makefile that gives a recipe for how to compile a given executable so that you can avoid retyping long compilation commands each time you need to compile a new version. In this case, the Makefile we provide (take a look!) uses gcc to compile your code with testing code and produces executable files named extest.bin and btest.bin.

Correctness: extest.bin and btest.bin

  1. extest.bin is a binary executable program that checks the functional correctness of the code in bits.c on the example test cases in the function headers in bits.c.

    The command ./extest.bin will run the example test cases for on all puzzle functions.

    $ ./extest.bin
    

    Don’t forget to (re-)compile a fresh version of the btest.bin executable each time you update bits.c.

    ... edit and save bits.c ...
    $ make
    $ ./extest.bin
    

    To simplify the recompilation process, you can instead use make extest as an abbreviation for the above sequence of commands.

  2. btest.bin is a binary executable program that checks the functional correctness of the code in bits.c using other testing code from btest.c.

    • Run tests of all puzzle functions with the command ./btest.bin, which runs the executable file btest.bin that was generated last time you compiled bits.c.

      $ ./btest.bin
      

      Don’t forget to (re-)compile a fresh version of the btest.bin executable each time you update bits.c.

      ... edit and save bits.c ...
      $ make
      $ ./btest.bin
      

      To simplify the recompilation process, you can instead use make btest as an abbreviation for the above sequence of commands.

    • To test an individual puzzle function, e.g., bitXor, pass the function name to btest.bin with its -f flag:

      $ ./btest.bin -f bitXor
      
    • Optionally, test an individual function with specific arguments using the flags -1, -2, and -3 to pass the 1st, 2nd, and 3rd arguments. For example, to test bitXor(7, 0xf), run:

      $ ./btest.bin -f bitXor -1 7 -2 0xf
      

Coding Rules: dlc

dlc is a modified C compiler that can check your solution against the coding rules.

$ ./dlc bits.c

A lack of output means your solution follows the coding rules. Error messages will appear if your solution violates the coding rules.

The -e switch supports counting operations in a function.

$ ./dlc -e bits.c

Summary: driver.pl

The driver.pl tool will automatically grade your solutions on correctness and performance using the dlc and btest.bin tools.

Points are awarded only for working solutions. The difficulty rating determines the number of correctness points available for each puzzle. Each puzzle may receive up to 2 performance points, based on the number of operations used.

Run the autograder like this (part of the output on our sample solution is shown):

$ ./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       6   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] (68 total operators)

Runnin make driver does this same thing as ./driver.pl.

Common Issues

You must use a CS 240 GNU/Linux computing environment for CS 240 code assignments.

The dlc checker enforces a stricter and older form of C declarations than gcc enforces. This section describes how to avoid common issues with dlc for the Bits assignment only. Do not adopt these as style conventions in later assignments.

Benign Warning in std-predef.h

You may receive one warning from dlc that you can safely ignore:

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

Pay attention to other warnings and errors.

Declare Variables at the Start of the Function

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 */
    return b+2;
}

Instead, you must declare all your variables first, like this:

int foo(int x) {
    int a = x;
    int b;
    a *= 3;
    b = a;
    return b+2
}

This restriction is specific to older standards for the C language, such as that used by the dlc checker. In future assignments, it will best practice and good style to declare variables at the innermost scope that is reasonable.

Avoid Binary Notation

Remember that unprefixed integer literals in C use decimal notation. The expression 10110010 in a C program means “the int value ten million, one-hundred ten thousand, and ten.”

The dlc checker does not accept the 0b prefix for numbers in binary notation (e.g., 0b11110000). Do not use it.

Instead, make good use of hexadecimal in this assignment: 0xF0. Or, for small numbers, decimal notation may work just fine.

The ishow.bin tool lets you display integer representations and conversions. It takes hex or decimal input.

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

Avoid #include

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.

Submission

Before submitting, disable any diagnostic printing in bits.c.

You will use the standard code assignment submission process for your answers in bits.c.

Submit: The course staff will collect your work directly from your hosted repository. To submit your work:

  1. Test your bits.c source code file one last time using ./driver.pl (or, equivalently, make driver). Make sure that, at a minimum, submitted source code is free of syntax errors and any other static errors (such as static type errors or name/scope errors). In other words: the code does not need to complete the correct computation when invoked, but it must be a valid program. We will not grade files that do not pass this bar.

  2. Use git status to see which files need to be added and committed. In this assignment, you should have changed only bits.c:

    [gdome@tempest bits] git status
    On branch main
    Your branch is up to date with 'origin/main'.
       
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   bits.c
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
  3. Make sure you have committed your latest changes. (Replace FILES with the files you changed and MESSAGE with your commit message.)

    $ git add FILES
    $ git commit -m "MESSAGE"
    

    In this assignment:

    [gdome@tempest bits] git add bits.c
    [gdome@tempest bits] git commit -m "finished all bits functions"
    [main aa41bff] finished all bits functions
    1 file changed, 3 insertions(+), 1 deletion(-)
    
  4. Run the command cs240 sign to sign your work and respond to any assignment survey questions.

    $ cs240 sign
    
  5. Push your signature and your latest local commits to the hosted repository.

    $ git push
    

Confirm: All local changes have been submitted if the output of git status shows both:

  • Your branch is up to date with 'origin/main', meaning all local commits have been pushed
  • nothing to commit, meaning all local changes have been committed

Resubmit: If you realize you need to change something later, just repeat the above process.

Grading

Your grade will be derived as follows:

  • Correctness and performance (72 points = 1.5 × autograder score):
    • Grading considers correctness and performance of all puzzle solutions.
    • Tests may include new inputs that btest.bin does not check by default.
    • Solutions must comply with the coding rules as checked by dlc.
    • No credit is awarded unless the ./driver.pl autograder can compile and run your code.
  • Succinct comments explaining why each puzzle solution works (28 points):
    • Grading may consider explanations for a random subset of puzzles.
    • Good comments describing incomplete or non-working solutions may receive credit in this part.

Correct solutions that match or beat the operator count of the instructor’s solutions may result in prizes!

  1. This document is an alternative description for the CSAPP Data Lab, which is available on the CSAPP website

  2. Different people have different opinions about which puzzles are more difficult.