CS1440 - Lab (4)
Various Kinds of Functions

The goal is to learn about:
    Predefined functions,
    Type casting using functions that convert variable types,
    Functions that return a value,
    Procedural abstraction and the importance of argument ordering,
    Scope of variables, and
    Function Overloading

Activity 4-1 - Preparations
Before we begin this lab, please change your directory to 1440 and in that directory, create the lab4 directory. Change to that directory and complete all your lab work in that directory.

Activity 4-2 - Predefined Functions
A function is a subprogram that is included in a C++ program to perform a particular task such as obtaining data, carrying out some calculations, displaying some information or messages, and displaying the output data.  In C++, there are many predefined functions that are written to simplify the computations.  Following is an example in which a predefined function is used.  This program is the same as the program given in the first question in your prelab assignment.  You were supposed to modify the program to compute 24, 33, 54, and 45 and display the results.

// P40.C This C++ program computes the value of 3^4.
#include<iostream.h>
int main(void)
{
      int i = 0, p = 1;
      int x = 3, y = 4;

      while(i < 4)
      {
             p = p * x;
             i++;
       }
       cout << x << " to the power of " << y << " is = " << p << endl;

       return 0;
}

The heart of this program is the part in red font.
Exercise 4.1
In the above program, P40.C, all variables are declared as int.  Could you modify this code to work for real values.  Thus, could you make changes such that it would compute something like 3.54.8.  Write your answer in a file called ex41 in the lab4 directory.

There is a predefined function in C++ that does this computation.  The function is called pow.  This function will take two numbers and will compute one to the power of the other.  For example, in the above program we want to compute 34, we can use p = pow(3,4) to compute it.  Thus, the above code can be simplified as:

// P40a.C - This C++ program computes the value of 3^4 using the pow function.
#include<iostream.h>
#include<math.h>
int main(void)
{
      int i = 0;
      int x = 3, y = 4;

     cout << x << " to the power of " << y << " is = " << pow(x, y) << endl;

       return 0;
}

Notice that we have included the math.h directive to be able to use the pow function.  Now that you learn about this function, you can complete the program to compute the rest of the values.

Exercise 4.2
Modify program P40a.C to compute 3.54.8 and to display the answer.  Call your new program ex42.C and save it under the lab4 directory.

// P41.C This program computes the 3^4, 2^4, 3^3, 5^4, and 4^5 and displays the results.
#include<iostream.h>
#include<math.h>
int main(void)
{
     cout << "3 to the power of 4 is "  << pow(3,4) << endl;
     cout << "2 to the power of 4 is "  << pow(2,4) << endl;
     cout << "3 to the power of 3 is "  << pow(3,3) << endl;
     cout << "4 to the power of 5 is "  << pow(4,5) << endl;

      return 0;
}

We also could include a while loop in this program to simplify the computation and make the program much better.

// P42.C This program computes the x^y.
#include<iostream.h>
#include<math.h>
int main(void)
{
      int choice = 1;
      int x, y;
      while(choice == 1)
      {
            cout << "Enter the x and y separated by a space, and I will compute x^y ";
            cin >> x >> y;
            cout << endl;

            cout << x  << " to the power of " << y  << " is = " << pow(x,y) << endl;
            cout << "\nDo you wish to compute another case, enter 1 to continue, 0 to end: ";
            cin >> choice;
      }
      return 0;
}

There are more predefined functions, here we will discuss few more.  As you may remember in lab2, you were asked to look into the quadratic equation.  The solution to a quadratic equation, AX2 + BX + C = 0, is:

The solutions were discussed in lab2.  Here, we only mention that before you could compute these two roots, you had to make sure that the value under the radical was not negative.  Another version of the program introduced in lab2 for computing the roots can be written as:

// P43.C This program solves the quadratic equation, AX^2 +  BX + C = 0
#include <iostream.h>
#include <math.h>

int main()
{
        double A,B,C,D;
        cout << "Enter A, B, C (without the commas): ";
        cin >> A >> B >> C;
        D = pow(B,2) - 4*A*C;
        if(D>0)
                cout << "The solutions are " << (-B+sqrt(D))/(2*A) << ", "
                << (-B-sqrt(D))/(2*A) << endl;
        else if(D==0)
                cout << "The solution is " << -B/(2*A) << endl;
        else
                cout << "There are no real solutions\n";
        return 0;
}

In the above program you used the predefined sqrt function to compute the square root of B^2 - 4AC.  For a more complete list of predefined functions, please see the Display 3.2 given in the text.

Exercise 4.3
Modify program P43.C such that is also displays the solution to the quadratic equation when A = 0.  Thus, when A = 0, it displays the value of -C/B as the answer.  Call your new program ex43.C and save it under the lab4 directory.

Exercise 4.4
Modify program P43.C such that is keeps asking for a new set of A, B, and C and computes the root(s) until the user decided to terminate the program by entering a negative value for the choice.  Call your new program ex44.C and save it under the lab4 directory.

Activity 4-3 - Round up and Round down Functions
Sometime in your calculations you may want to round your results up and/or down.  There are two predefined functions that are used for this purpose.  The function ceil will round up a given real number to its next whole number and function floor will round down a given real number to its lower whole number.  Examples:

if x = 34.3    then y = ceil(x) is 35.0
if x = 34.3    then y = floor is 34.0

Exercise 4.5
Write a C++ program, ex45.C, to compute the ceil and floor of any input value.  Then compute the ceil and floor of -34.5 ?

We also have two functions that are used to take the absolute value of an integer or a real value.  The first one is called abs that is used to compute the absolute value of an integer.  Example:  x = -4, then y = abs(x) will be 4.  The other function is fabs that computes the absolute value of a float or double type number.  Example:  x = -3.43, then y = fabs(x) will be 3.43.

Activity 4-4 -Type Changing Functions - Type Casting
In problem 3 of the prelab, you were asked to determine a possible source of error in the given program.  Perhaps, you have found that dividing two integers will not always result in the correct answer.  For example, that program produces 0 when you divide 2 by 4 as integers.  There is a way to fix this problem using predefined functions.  The type changing functions allows us to change the type of a variable at the line that is used. For example, in the code given in problem 3, one can change the variable type of the numerator (type cast) to float, so the division will become a float divided by an integer.

#include<iostream.h>
int main(void)
{
      int x,y;
      cout << "Enter 2 values for x and y separated by space, then press <Enter> :";
      cin >> x >> y;
      cout << endl;

      cout << x << "/" << y << " = " <<float(x)/y << endl;

      return 0;
}

The change is shown in red font for clarity.  Note that variable x will stay an integer regardless of the float(x)/y statement.  Type casting will not change the type for x, instead float(x) will be the float type value with the same value as x that will be used in the division.

Activity 4-5 - Functions that return a value
We can write our own functions to perform some computations.  The following program from your text will compute the total cost of purchases made in a store.  In this program, we will use a function that computes the cost plus 5% sales tax of  purchases made.

// P44.C This program computes the total cost of purchases made,
//including 5% sales tax, on number_par items at a cost of price_par each.
#include <iostream>

double total_cost(int number_par, double price_par); // (1) Function prototype

int main( )
{
        double price, bill;
        int number;

        cout << "Enter the number of items purchased: ";
        cin >> number;
        cout << "Enter the price per item $";
        cin >> price;

        bill = total_cost(number, price); // (2) Function call

        // The following three lines are used for formatting purpose.  Since a precision of 2
       //  is set, then all numbers will be displayed with two decimal points.  We work with $
       //  that is the way it should be.
        cout.setf(ios::fixed);
        cout.setf(ios::showpoint);
        cout.precision(2);

        cout << number << " items at "
                 << "$" << price << " each.\n"
                 << "Final bill, including tax, is $" << bill
                 << endl;

        return 0;
}

// (3) Function definition
double total_cost(int number_par, double price_par)  // Function heading
{ // Function body begins here
        const double TAX_RATE = 0.05; //5% sales tax
        double subtotal;

        subtotal = price_par * number_par;
        return (subtotal + subtotal*TAX_RATE);
}// Function body ends here

As you can see, we have used a function called total_cost to compute the cost + 5% tax.  Note that this function has computed the total cost and has returned a single value at return (subtotal + subtotal*TAX_RATE); The returned value is of type double.

Remarks
There are 3 things that you must remember when you work with functions.

    1) A function must have a name, in the above program name was total_cost
    2) A function must have a type, the type for the above function is double
    3) A function must have correct parameter definitions.  This means that the parameters, if any, must have type consistency and correct ordering at the a) function prototype, b) function call, and c) function definition.

Violation of any of these three will result in syntax or logical errors.

Please note that the function used in the above program is of type double.  Thus, it returns a value of type double and in the main function, that value was received by a variable of type double at:
bill = total_cost(number, price);

where bill is defined as double in the main function.

Procedural Abstraction and Parameter Ordering
A function must be written like a black box.  The user does not need to have any knowledge of the details in the body of the function.  He/she should be able to determine what the function will do by looking at the function prototype and provide the correct input values with correct types to obtain the correct result from a function.

A function may have several parameters of different types.  It is critical that the parameters passed to a function have the same order at a) the function prototype, b) the function call, and c) the function definition.  Violation of the correct ordering may result in a) syntax error or b) logical error.  It is very hard to find the error when the ordering is incorrect.  So if you get an error when you are using a function, the first thing you may want to check is the type and ordering constancy in all instances of the function.

Scope of a variable
The scope of a variable declared inside a function is the body of that function.  For example, in the above program variable bill declared inside the body of the main function.  Thus, bill is unknown in the total_cost function.  If we attempt to use bill without declaring it in the function total_cost, we will get a syntax error that bill is undeclared.  Similarly, variable subtotal is unknown to the main function, because it is a variable defined in the total_cost function and its scope is the body of the total_cost function only.  These types of variables are referred to as local variables.  They are local to the function in which they are declared.  There are, however, a method to define a variable such that it is known to all functions.  This type of variables are defined at the top of the program right after the include directives.  Any variable defined this way is known as global variable.

The parameters passed to a function are also local to the function within which they are defined.  Thus, a parameter that may go through changes inside a function that is called by another, will assume its original value upon the completion of the called function. This is referred to as call_by_value. The following example will help you understand all these definitions.

// P45.C This program illustrates the local and global variables and call-by-value.
// This program computes the side area and the cross section area of a cylinder
#include<iostream.h>
#include<math.h>

double PI = 3.14159;  // This variable is defined globally, known to all functions in this program as PI

double Cross_area(double r);  // Function prototype for function Cross_area
double Side_area(double r, double h);  // Function prototype for function Side_area

int main(void)
{
     double h, r;

      cout << "Enter the radios and the height of the cylinder in Cm <Enter> ";
      cin >> r >> h;
      cout << endl;
      cout << "Before I do any computation or call any function, I want to let you know that \n";
      cout << "you have entered r = " << r << " and h = " << h << endl;

      cout << "The cross section area of the cylinder is " << Cross_area(r) << endl;
      cout << "The side area of the cylinder is " << Side_area(r,h) << "\n\n";

      cout << "By the way, I am r and my value is " << r << endl;
      cout << "My value is reset to whatever it was in the main before you called the function, \n";
      cout << "this is because, you send me there as call_by_value \n";

      return 0;
}

double Cross_area(double r)
{
      return PI*pow(r,2);
}

double Side_area(double r, double h)
{
      double area;
      area = 2*PI*r*h;
      r = r * 1000;  // just to show what will happen to r

      return area;
}

In the above program, r and h are declared in the main function and are local to that function.  These two have been passed to the function Side_area with the same names but they are still local to both functions regardless their names. But, PI is defined globally and will be known to all the functions as PI.  If by any chance the value for PI changes in one of these functions, every function which is using PI will use it with its new value. That is why it is a good practice to define a constant that is defined globally using const so its value is unchangeable.  For example, PI should be defined as:  conts double PI = 3.14159;

Activity 4-6 - Function Overloading
In the above program, we have used two different function names to distinguish between the function that computes the cross area and the one that computes the side area.  Using overloading we can give both function with the same name.  The selection will be made based on their prototypes.  Here is the new version of the same program written using overloading.

// P46.C This program illustrates the local and global variables and call-by-value.
// This program computes the side area and the cross section area of a cylinder
#include<iostream.h>
#include<math.h>

const double PI = 3.14159;  // This variable is defined as a constant globally

double Area(double r);  // Function prototype for function that computes the cross section
double Area(double r, double h);  // Function prototype for function that computes the side area

int main(void)
{
     double h, r;

      cout << "Enter the radios and the height of the cylinder in Cm <Enter> ";
      cin >> r >> h;
      cout << endl;
      cout << "Before I do any computation or call any function, I want to let you know that \n";
      cout << "you have entered r = " << r << " and h = " << h << endl;

      cout << "The cross section area of the cylinder is " << Area(r) << endl;
      cout << "The side area of the cylinder is " << Area(r,h) << "\n\n";

      cout << "By the way, I am r and my value is " << r << endl;
      cout << "My value was changed in the 2nd Area function, \n";
      cout << "but it is reset to whatever it was before you call that function.\n";
      cout << "This is because, you send me to that function using call_by_value. \n";

      return 0;
}

double Area(double r)
// Computes the cross sectional area of the cylinder
{
      return PI*pow(r,2);
}

double Area(double r, double h)
// Computes the side area of the cylinder
{
      double area;
      area = 2*PI*r*h;
      r = r * 1000;  // just to show what will happen to r

      return area;
}

Exercise 4.6
Could you use overloading to compute the area and volume of an sphere with two functions that have the same name? Explain your answer.  Write your answer in a file called ex46 and save it in your lab4 directory.

Exercise 4.7
Modify program P46.C to compute the side area, total area, and volume of a cylinder and the area and volume of a sphere, depending on the choice that user makes.  Your program should ask users to decide whether the shape is an sphere or a cylinder, then display the result for the selected shape.  Here is the definitions you may need for a cylinder with radius r, and height h:
    Side area: (2*PI*r) * h
    Total Area: 2*(PI*r2) + Side area
    Volume: (PI*r2)*h

Call your new program Ex47.C and save it under the lab4 directory.

Post Lab Exercise
Modify program P44.C to compute the total cost of the purchases differently.  This time if the price per item is more than $20, a special discount will be applied.  The special discount varies depending on the day of the week or the occasion, so you have to ask for the special rate of discount at the time of purchase.  For now, you ask the user to enter a rate between 5-20%.  For items with price per item of less than $20, use the same calculations as before.  You need to use function overloading in your new program.