Parameter Passing and Overloading (param)
CS 330 - Spring 2008 - Dr. Liffick

Due: Classtime, April 21.

Goals
 
- to better understand how parameter passing works
- to use function name overloading
- to build a C++ macro
- to understand pass-by-name and Jensen's Device
- to remember dot products and matrix multiplication

Overview

In this lab you will use the macro facility of C++ to investigate pass-by-name, Jensen's Device, and overloading functions.

When you are done with this project, you should submit the final param.cxx file as lab param to liffick330. I need only the param.cxx file that you modified. It should contain the macro, functions, and driver described below.

I expect your code to use functions extensively, have appropriate comments, and to pass parameters correctly. In particular, there should be two read, two write, and two multiply functions. Those function names are overloaded. All real number values should be printed with two digits after the decimal point. Both vectors and both matrices should be printed neatly.

Getting Started

You will find the files supporting this lab on the course webpage. There are tvector and tmatrix class definitions in tvector.h and tmatrix.h along with their implementations (.template files). We're using these versions because the standard template library does not have a matrix class. There is a very skeletal program there called param.cxx that has the appropriate include directives to get to those files. You should not change these library references in your program.

You should copy only the param.cxx file to your space. You can compile it normally. However, to see how the preprocessor expands macros, you can compile with the -E option and save the output:
   g++ -E param.cxx > afterPre
Look at the afterPre file with your editor and look way down at the bottom (after all the .h files have been included; you can search for the harpo variable name). Notice how the macro call has been expanded with its parameters substituted as text.

What You Need to Build (and do it incrementally to make the task easier)

Write a driver that reads integers J, K, and L and declares two tvectors of type double and size J and two tmatrices of type double and size JxK and KxL The values of the vectors and matrices are initialized by reading them from the input. Read the two vectors first, then the JxK matrix and KxL matrix in row-major order. Print the results of norm for both vectors, dot product of the two vectors, and matrix multiply of the two matrices.

Be SURE you read the values in EXACTLY the order specified above. Initially, you may read J, K, and L and then the first vector.

Write a function read that has a single vector parameter that has elements of double type and fills the vector from standard input. Remember that the tvector class has a size( ) function. Realize that the tmatrix class has functions named numrows( ) and numcols( ). In both cases, it is good software engineering to store those values (or values calculated from them) in local variables rather than calculating them every time through a loop.

Write a function write that has a single vector parameter that has elements of double type and prints the vector with 8 characters per value, printed with 2 digits after the decimal point.

Implement Jensen's Device as a C++ macro called jensen. Refer to exercise 16 on p. 412 of the text where they note that the expression and the counter are passed by name. The formula at right shows what you are computing in another way. A similar chunk of code that seems more readable than that in the text is:
 
function sum(expr, index, start, stop)
begin
  temp = 0;
  for index = start to stop
    temp = temp + expr;
  end for
  return temp
end sum
Jensen formula
It should have starting and stopping parameters. Macros can't return a value; the macro code is textually placed in the code in place of the macro call. Therefore, write this as a procedure rather than as a function and have an extra parameter for the sum.

The param.cxx file has a macro example to help you a bit. Note that you need a backslash (\) as the last character of a line if you need to continue your macro onto multiple lines. Using multiple lines makes the code more readable. Do not have a space between the macro name and the following open parentheses.

Test your macro by summing the values in your first vector and printing that result. If you wanted to write this as a mathematical formula using the summation sign, how would you write it? Getting the macro part working correctly now will make the rest of this project remarkably easier.

Write a function called norm that takes a vector as its only parameter and returns the norm of the vector. The norm is defined as the square root of the sum of the squares of the vector's coordinates (elements). Use Jensen's Device to calculate the sum of the squares of the coordinates. The elements and results will be type double. Pass the vector appropriately into this function. Print the norms of both vectors neatly with labels.

Write a function multiply that takes two vectors and computes their dot product. It should use Jensen's device.

Write a function read that has a single matrix parameter and that fills the matrix from standard input by reading in row major order.

Write a function write that has a single matrix parameter and writes the matrix to standard output, in row major order, with 10 characters per value, printed with 2 digits after the decimal point.

Write another function multiply that takes two matrices and computes their product. Use the tmatrix class provided with this assignment. It should also use Jensen's device to compute each element of the final matrix. Note that this function will have loops to visit each element of the resulting matrix. It should return a reference to newly allocated space for the resulting matrix of the appropriate size. The return type is reference to tmatrix (see below). Your matrix multiply should not call your vector multiply function.

Be sure you use appropriate parameter passing mechanisms for each function.

Notes and hints

Syntax errors inside the #define will NOT be detected on that line. They will show up as errors where the macro is used.

To allocate a new matrix and create a reference to it you'll need to do a declaration such as:
   tmatrix<double> & m = *(new tmatrix<double>(rows,cols));
Then you can use the variable m as normal. e.g. m[i][j]. You can also return it from the function. Note that the instructions say that the matrix multiply instruction should return a reference to a tmatrix.

Sample Output

I expect you to create your own test cases. Hint: Zeros are nice for hand calculating the expected answers. Compute your expected output before running your program. I will try only valid input (no negative sizes or missing data). The following sample output gives a general form. However, all values should be printed with two digits after the decimal point. The matrix should be printed as described above. You may print more information than is shown here.

a is     4.00    5.00
Norm of a is 6.40
b is    -2.30    5.00
Norm of b is 5.50
Dot product of a and b is 15.80
c is
      3.00      4.00      0.00
      1.00      0.00      5.00

d is
      4.00      0.00      1.00      1.00
      0.00      1.50      2.00     -1.00
      1.00      0.00      0.00      2.00

The product of c and d is
     12.00      6.00     11.00     -1.00
      9.00      0.00      1.00     11.00