CS255 C program 2 - Handling Bitmaps and Pointers in C.

• Assignment

• Remark:

 This homework is adapted from the CS450 Assignment 1 that Prof. Mandelberg uses to measure the ability of students to program in C... I have modified it and added instructions that he gave in class to students.

• Description:

• Complete a C program that takes one command line argument (N) and:

 Find all prime numbers that are ≤ N Then reads in integers from the terminal and uses the prime numbers found to factor the integer inputs.

• Provided files

• This project uses the following files: (right click on the links and save in your project directory)

 header.h: header file containing the bit array (linked list) structure used in this project main.c: the test program that invoke the functions that you must write Makefile: make file

I will describe the header.h and main.c below.

• Data structure used in the project

• This project reinforces your understanding of linked lists and bit manipulation

• The project will still implement the Sieve of Erathothenes so you don't have to write the algorithm from scratch, but adjust the solution (I will have posted my solution SieveOfE()) by the time this homework is handed out).

• We will use a different way to represent a bit array than in project C1

• The data structure used to represent prime numbers in this project is defined in header.h

• Description of the data structure used in this project:

• The bit array (used to represent prime numbers) is stored as a linked list (pointed to by the variable head) and each list element contains a bit array of 256 × 32 bits:

We call one such piece of the bit array a segment

• The definition of the segment data type is as follows (see header.h):

 ``` #define SIZE_OF_SEG 256 // 256 int per segment typedef struct _seg { int bits[SIZE_OF_SEG]; // # bits in bits[] array = SIZE_OF_SEG struct _seg *next; // Link to the next segment } seg; // User defined type #define BITS_PER_SEG (8*SIZE_OF_SEG*sizeof(int)) EXTERN seg *head; // This variable points to the // start of the linked list of segments !!! ```

• The main program has code to construct a linked list containing sufficient number of segments to represent numbers ≤ N

(The number N is an argument of the main program, just like the first C program)

Here is the progarm code in the main program that constructs the linked list of segments of bit arrays:

 ``` /* ======================================================= Allocate the linked list of segments containing pieces of the bit array ======================================================= */ NSegs = N/(2*BITS_PER_SEG) + 2; // You need NSegs segments head = NULL; // Empty list for (i = 0; i < NSegs; i++) { p = ( seg *) malloc(sizeof (seg)); // Make a new segment p->next = head; // Add the next segment to the list head = p; } ```

• So you don't have to make this list, just use it.

• How to use the bits in the segmented bit array to represent prime numbers

• In the previous C programming project, we use bit i in the bit array to represent whether the number i is prime or not prime

• In this C programming assignment, we will improve the efficiency and use the bit array to represent odd numbers only.

Example:

Explnation:

 The figure above show the bit array portion in segment 0. Bit 0 in array element bits[0] represents the first odd number (0) Bit 1 in array element bits[0] represents the second odd number (3) Bit 2 in array element bits[0] represents the third odd number (5) And so on.

• Description of the main program and the functions that you must provide to complete the program

• The main program (provided in main.c) does the following: (you do not need to make any changes to it !!)

 ``` /* ------------------------ Initialize bit array ------------------------ */ clearAll(); /* ------------------------ Find primes ------------------------ */ sieveOfE( N ); // Modify my solution in C project 1 !!! numOfPrimes = countPrimes( N ); printf("Number of primes found = %d\n", numOfPrimes ); if ( numOfPrimes <= 100 ) printPrimes( N ); while (1) { printf("Enter number >> "); if ( scanf("%d", &inp) == EOF ) { break; } factor(inp); } ```

• The main program first clear out the segmented bit array (linked list) (fill with 0's)

 You must write the clearAll() function that clear out the segmented bit array (linked list) (the variable head points to the first segment --- the next field in the last segment has the value NULL)

• Then it finds all the odd prime numbers (stores them in the segmented bit array (linked list) (that starts at head)

• You may use my posted solution for C project 1, but you must modify the posted solution appropriately (it does not work without changes - figure out what needs to be changed)

 Hint: The changes are minimal (very small) !! You have to add an if statement around some statement in several places in SieveOfE() (because the sieve algorithm can skip over the even numbers... why can you skip ? because the bit array only contain odd prime numbers, you don't need to process even numbers) Change the parameter to the testBitIs0() because the meaning of the parameter is changed.

• You do need to re-write the following functions that are used by the SieveOfE(N) function: (I have detailed what the functions must do)

• void setBit( int n ):

 ``` Note: the input n is the bit position in the segmented bit array. The bit position n represents the number (2*n+1) as given in the figure above ! 1. find the segment that contains the portion of the bit array used (See a programming hint below) 2. find the array index i of bits[i] in segment 3. find the bit position pos 4. set that bit position ```

• int testBitIs0( int n ):

 ``` Note: the input n is the bit position in the segmented bit array. The bit position n represents the number (2*n+1) as given in the figure above ! 1. find the segment that contains the portion of the bit array used (See a programming hint below) 2. find the array index i of bits[i] in segment 3. find the bit position pos 4. test if that bit position is 0 ```

• The main program then prints a count of the number of primes found and print out a list of primes if there are ≤ 100 primes.

 You must write the countPrimes(N) and printPrimes(N) functions --- use the primes stored in the segmented bit array (linked list) (the variable head points to the first segment)

• Finally, the main program reads in a number of integers and call factor() to print out factor each input.

• You must write the factor(inp) function:

 ``` 1. first, factor and print out all the number 2's from the input inp 2. then use the odd prime numbers stored in the segmented bit array to find and print the odd factors ```

• Put all your functions inside a file named:

 ``` primes2.c ```

Make sure your primes2.c program file include the following files:

 ``` #include #include "header.h" ```

Otherwise, your program can't use the correct data type nor variable head !!!

• Programming hints

• You must first work out how to find these values:

 The segment number of the segment that store the bit position represent the number n The index i of the array bits[i] within that segment that store the bit position represent the number n The position pos within the array element bits[i] that represents the number n

If necessary, use printf() within the setBit() and testBitIs0() functions to print out n, the segment number, the array element index and the bit position to help you check the computation.

• You can use the following loop to go to the kth segment:

 ``` seg *p; int j; p = head; for ( j = 0; j < k; j++) p = p->next; ```

When the loop ends, the pointer variable p will point to the kth segment in the list.

• To help you debug, you should write a dummy factor() function initially:

 ``` void factor( int inp ) { } ```

and test your program. This way, you can make sure that the SieveofE() finds the prime numbers correctly.

Use your first program to check (the outputs should be the same !)

• Note:

 Do not update the head variable ! Otherwise, you will lose the linked list !!!

• Compile and run

• Use this command to compile:

 ``` make ```

You make have save a copy of all the provided files and have written the necessary functions in "primes2.c" before you can make

• Use this command to compile:

 ``` main ```

 ``` ./main ```

Your PATH variables dies not include the currect directory. To fix this, add . (period) to your PATH variable.

• Note:

 I have set the debug flag (-g) in the Makefile so if you get a core dump, use gdb main and run the program to see which statement caused it to crashes.)

• Sample output

 ``` main 10000 Number of primes found = 1229 Enter number >> 456 2 2 2 3 19 Enter number >> 12345 3 5 823 Enter number >> control-D (type control-D to end input) Done ```

• Bonus credits: Speed up the setBit() and testBitIs0() functions

• When you run your program for N = 32000000, you will notice that the program takes a very long time (I killed it before it found all the primes after 3 mins).

• The reason why it is so slow is the fact that the setBit() and testBitIs0() functions must traverse the linked list from the start each time

• For 20 pts bonus credits:

 Modify the setBit() and testBitIs0() so that they remembers the current segment The setBit() and testBitIs0() will use the current segment if the required segment is the current segment (i.e., no traversal) The setBit() and testBitIs0() will start the list traversal at the current segment if the required segment is "downstream" (further down) in the list. The setBit() and testBitIs0() will only start the list traversal at head if the required segment is "upstream" (= ahead) in the list.

• Using the debugger gdb

• I don't want to teach debugging (because I don't believe debugging is part of "Computer Science"). I do know that you need to learn debugging, and need to learn to use a debugger. So I have written a page to show you how to use the gdb debugger:

• Turnin

• Turn in your project with this command:

 ``` /home/cs255000/turnin primes2.c c2 ```