EECS 258 - Laboratory Assignment 6

The objective of this laboratory assignment is to introduce you to the notion of "problem decomposition" using functions. We will focus on defining new functions, calling functions, using return values, and debugging functions. In addition, automated unit testing with assert() will be covered. This assignment has the following steps:

  1. Generating random numbers
  2. The rand function generates a random integer between 0 and RAND_MAX (a symbolic constant defined in the <stdlib.h> header file). The minimum value of RAND_MAX must be at least 32767. If we want a to generate random numbers to simulate the throw of a dice, then all we need is numbers between 1 - 6. To achieve this the mod % operator is used:
    1 + rand % 6 will return a random number from 1 to 6.

    The rand function is actually a pseudo-random number generator. Calling rand repeatedly produces a sequence of numbers that appears to be random. However, the sequence repeats itself each time the program is executed. The following example illustrates this.

    The given program is a simulation of a very basic online Roulette spinning wheel. It is based on a single number bet. The returns usually are 35 to 1. Cut and paste this program into a cpp file and execute more than once. Follow the sequence of values closely.

    //-------------------------------------------------------
    // Roulette.cpp
    // Program to demonstrate rand() and srand() functions.
    // Author Suchit Batheja
    // Fall 2003 
    //-------------------------------------------------------
    
    #include < iostream >
    #include < cstdlib >
    #include < ctime >
    using namespace std;
    
    int main()
    {
       int Number;
       double Bet;
       int Roule = 0;
    
       // Repeat until user quits
       char Ch = 'y';
       while ((Ch == 'Y') || (Ch == 'y'))
       {
          // Get number
          Number = -1;
          while ((Number < 0) || (number > 36))
          {
    	 cout << "enter number to bet on (between 0 - 36) " << endl;
    	 cin >> Number;
          }
    
          // Get bet
          Bet = 0.0;
          while (Bet <= 0.0)
          {
    	 cout << "enter bet amount" << endl;
    	 cin >> Bet;
          }
    
          // Spinning the wheel
          Roule = rand() % 37;
    
          // After Spinning 
          cout << "lucky number is  " << roule << endl;
          if (number == roule)
    	 cout << "congratulations!! you have won " << (35 * bet) << endl;
          else
    	 cout << "oops you lost. better luck next time :-(" << endl;
          cout << endl << "play again y/n" << endl;
          cin >> Ch;
       }
       return 0;
    }

    If you noticed, the random number sequence generated over different executions are the same. This is useful if you wish to run the same experiments again, but not good for a game of chance. To overcome this problem a function called srand(unsigned int) can be used to change the starting point of the sequence.

    If the seed remains the same over multiple executions then the sequence generated is again pseudo random. If the seed is made based on the system time, it will be different every time we run the program and we will get a different random sequence every time. Insert this line of code in your program: srand(time(NULL)); The seed is now set to the current time. Now see how lucky you get.

    Program output

  3. Writing automated unit tests with assert()
  4. Another useful function (actually its a macro) in the C++ standard library is assert(). assert() is defined in the standard include file cassert. assert() takes one parameter which is a boolean expression. If the expression evaluates to true, then nothing happens when the assert() is executed. If the expression evaluates to false, then the program halts at that point and prints a message indicating the line and the expression of the failing assert().

    assert() statements can be added to your programs to test your code. For instance, the following program uses assert() to verify that the sum() function works correctly.

    //-------------------------------------------------------
    // sum.cpp
    // Program to demonstrate assert() macro.
    // Author David Janzen 
    // Fall 2005 
    //-------------------------------------------------------
     #include <iostream>
     #include <cassert>
     using namespace std;
    
     int sum(int min, int max);
    
     int main()
     {
       assert(sum(3,7)==25);
       assert(sum(-2,3)==3);
       assert(sum(-5,5)==0);
       cout << "No errors encountered" << endl;
     }
    
     // This function sums the integers
     //   from min to max inclusive.
     // Pre: min < max
     // Post: return-value = min + (min+1) + ...
     //   + (max-1) + max
     int sum(int min, int max)
     {
       int sum = 0;
       for(int i=min;i<=max;i++)
       {
         sum += i;
       }
       return sum;
     }
    

    Add three more assert statements to test the sum() function. For instance, pass in two negative numbers or make both parameters the same number.

    Your main function

  5. User defined functions
  6. The following functions can be used to calculate the volumes of three different solids. Show how you should call each of these functions in the main function to perform the specified tasks. Make sure the data types on parameters and return values match the function definitions.

    //-------------------------------------------------------
    // Author: John Gauch
    // Date:   Fall 2003  //tests added by David Janzen Fall 2005
    //-------------------------------------------------------
    #include <iostream>
    #include <cassert>
    using namespace std;
    
    // Function prototypes
    float cubeVolume( float sideLength );
    double sphereVolume( float sidelength );
    int cylinderVolume( float radius, int height );
    
    // Calculate the volume of a cube
    float cubeVolume( float sideLength )
    {
       return ( sideLength * sideLength * sideLength );
    }
    
    // Calculate the colume of a sphere
    double sphereVolume( float radius )
    {
       return ( (4.0 / 3.0) * 3.14159 * radius * radius * radius );
    }
    
    // Calculate the volume of a cylinder
    int cylinderVolume( float radius, int height )
    {
       return (int) ( 3.14159 * radius * radius * height );
    }
    
    // Main function to test volume functions
    int main( int argc, char * argv[] )
    {
       // Use assert() to write a test to compute the volume of a cube whose sides are 4 long
    
       // Use assert() to use a sphere radius and output volume
    
       // Use assert() to calculate the volume of a Pepsi can (or Coke if you prefer)
    
       cout << "No errors encountered" << endl;
    
    return 0;
    }

    Your main function

  7. Write a short function
  8. N Factorial is equal to the product of all integers from 1 to N. Specifically, factorial(N) = N x (N-1) x (N-2) x ... x 2 x 1. Write an iterative function that performs the N Factorial calculation. The function should take an int as a parameter and return an int as the result of the function.

    Write a short program that uses assert() to test your factorial function. Place all your assert() statements in a run_tests() function like this:

     void run_tests();
    
     int main()
     {
       run_tests();
     }
    
     void run_tests()
     {
       { //test 1 
         assert(  /* fill this in */ );
       } //test 1
    
       { //test 2
         assert(  /* fill this in */ );
       } //test 2
     }
    

    Tests like these are called unit tests because you are testing one unit (a function) of your program. Writing tests after you have written some code is called test-last programming. An alternative is to do test-first programming where you write a test first, then write a function to make the test pass, then repeat to write another test. Notice that test-last programming primarily uses tests to verify that the code works correctly, while test-first programming forces you to make design decisions such as the function name, the function parameters, the function return type, and the function's expected behavior when you are writing the test. We will apply a test-first approach in lab next week.

    Now that you have tested your factorial function, extend your program so that it prompts the user for a value of the N to calculate factorial. The program should output the result of the calculation, then prompt the user again. It should prompt the user until the user enters a value of zero. Then the program should exit. Leave the tests in the program. You can comment out the call to run_tests() if you don't want them run.

    Here is a sample of what your output might look like:

    	> Enter value of N: 3
    	Factorial(N) = 6
    	> Enter value of N: 5
    	Factorial(N) = 120
    	> Enter value of N: 0
    	End of program.
    

    Your factorial program

  9. Run the program
  10. Test the program you created by calculating two or three typical values and copy the output of the program below. See if you can "break" the program by changing what you input. Tests like these are called integration tests because you are putting everything together, or if the user is running them they are called acceptance tests because you are seeing if the whole program functionality is acceptable. Cut and paste your results below.

    Your program output

  11. Debugging a program
  12. The following program uses functions to generate the multiplication table of the number passed to the function. It was developed without any unit tests. Identify the errors present in the program and correct them. Add comments to the program to explain what each function does.

    //-------------------------------------------------------
    // Author: Abhishek Shivadas
    // Date:   Fall 2003
    //-------------------------------------------------------
    
    #include <iostream>
    using namespace std;
    
    void multiply_by_two(int number);
    int multiply_by_three(int number);
    
    int main()
    {
    
     	float number_two;
    	char  number_three;
    	int number_four;
    
    	cout << "Enter the Number to multiply by two:" << endl;
    	cin >> number_two;
    
    	cout << "Enter the Number to multiply by three:" << endl;
    	cin >> number_three;
    
    	cout << "Enter the Number to multiply by four:" << endl;
    	cin >> number_four;
    }
    
    void multiply_by_two(float number)
    {
    	int i;
    	for(i = number; i <= 9; i++)
    		cout << i << "times 2 is" << number * 2;
    
    	return i;
    
    }
    
    int multiply_by_three(int number)
    {
    	int i;
    	for(i == number; i <= 9; i++)
    	{
    	       number = number * 3;
                   cout << i << "times 3 is" << number * 3; 	   
    	       return number;
    	}
    	
    }
    
    int multiply_by_four(int number)
    {
    	int i;
    	boolean finished_calculating = true;
    	for(i = number; i <= 9; i++)
    		cout << i << "times 4 is" << number * 4;
    
    	return finished_calculating;
    }
    

    Create a C++ program called Number_Functions.cpp, and use "cut" and "paste" to copy the text above into the same. What errors do you get when you try to compile the program? Before you start correcting these errors, edit the file to add comments describing the purpose of the program, the author, and date at the top of Number_Functions.cpp. Now, start entering your corrections to make the compile errors go away. As a general rule, it is best to start with the first error message and recompile until that error is corrected.

    For each correction, make a comment near the code you corrected indicating what you did. This way, you can remember what you did. When you work on joint programming projects everyone can keep track of changes to the code by reading everyone's comments. Ponder over the warnings which appear while compiling the code and if possible try to correct the warnings as well. The output of the above program should be like this:

    	"Number" times "2 or 3 or 4" is "Answer"
    			 .
    			 .
    			 .
    			 .
    			 .
    	9 times "2 or 3 or 4" is "Answer"
    

    Corrected code

    Output here

  13. Submit Your Work
  14. This lab assignment will be submitted electronically to the TAs once you fill in the fields below and click on the "submit" button. You do NOT need to print a copy of this document to hand in.

    Your full name:
    Your kuid number:

    If you are ready to send the lab to the grader, click on the submit button. Otherwise, go back and fill in any missing pieces and then submit your work.