EECS 370 - Classes and Operator Overloading

Machine Problem 3

Due date: Thursday October 21, 1999 at 11:59 pm
Extented to: Monday October 25, 1999 at 11:59 pm

Driver programs to test out you library:

  1. driver1.cpp - Uses Unum only
  2. driver2.cpp - Uses Unum only
  3. driver3.cpp - Uses Matrix and Unum
  4. makefile - to be turned in

For this assignment you are write a library "numbers.h" that will be used by others. The library will contain two classes Unum and Matrix.

The class: Unum

The class Unum is essentially a complex number. The name Unum stands for Universal NUMber. The idea of this class is to allow for the storage of any numeric value whether the value is of integer, floating point or complex number format. This only time that the format of the number will come into play is when dealing with input and output. Internally in the class, all values will be considered as a complex number that has both an real part and an imaginary part. The purpose of this is to free the programmer from concern about type conversions between these different numeric types. Both the real and imaginary part of the complex number are to stored using the type double.

For the stream output operator, <<, if the value has no imaginary part, only the real part should be written (i.e. the value of 5.275+0.0i should output as 5.275). Also, if the real or imaginary parts have no fractional value, the value should be written as an integer (i.e. 3.0+0.0i should be 3, 5.0+9.0i should be 5+9i, 3.25+2.0i should be 3.25+2i, -3.0+-3.14159i should be -3+-3.14159i). The <math.h> library function modf() may be useful for this conversion.

For the stream input operator, >>, when the imaginary part of the number will be 0.0, the input can be a single integer or single floating point value. When there is both a real part and an imaginary part, the value for the real part will be given first and will be immediately followed by the '+' character, the imaginary part and the character 'i'. There will be no white space contained in the value. The values for the real and imaginary part can be either an integer or a floating point value.

In addition to overloading stream input and output operator, the following operators are to be overloaded:

     ++ (postfix and prefix)      increament real part by 1
-- (postfix and prefix)decrement real part by 1
unary - change sign of real part
unary + keep sign of real part
* multiplication - use polynomial multiplication
(a+bi) * (c+di) = ac + adi + cbi + bdii = ac + adi + cbi - bd
/ division
X / (a+bi) = (a+-bi) * X / (a2 + b2)
binary + addition
binary - subtraction
= assignment
==equality
Only compare the imaginary parts if the real parts are equal. If the real parts are not equal, use this information do resolve the relational operator.
!= inequality
< less than
<=less than or equal
>greater than
>= greater than or equal
bool() convert to type bool
false == 0+0i, true != 0+0i
long() convert to type long
convert the real value to an integer of type long
double()convert to type double
convert the real value to a floating point of type double

The class Unum must also have a constructor that takes two parameters. The first parameter corresponds to the real part of the complex number, the second parameter corresponds to the imaginary part. Both of these values are to default to zero if not given. Also, they are to allow for either integer or floating point values. An instance that is created with integer values should print out integer values for its output. Write any other constructors, destructor or methods that you feel are necessary.

The class Unum must also have two functions written for it (note these are functions not methods). These are the functions of pow() and sqrt(). The prototypes for these functions is as follows:

     Unum pow(Unum base, int exp);
     Unum sqrt(Unum sqr);
The function pow() is to return the value in base raised to the power of exp. The function sqrt() is to return the square root of sqr. To keep things simple for sqrt(), if the imaginary part of sqr is not zero, print a warning message and only determine the square root of real part.

The class: Matrix

The class Matrix will be a two dimensional matrix of type Unum. This storage space for this class must be dynamic. Since dynamic two dimensional arrays seem to give people a fair amount of trouble, you may wish to synthesize a two dimensional array with a single dimensional array.

For the stream output operator, <<, you are to first print the dimensions of the matrix (number of rows, then number of columns) followed by the values in the matrix list one row at a time. For the stream input operator, >>, the first two values read indicate the number of rows followed by the number of columns. After this all of the values from the matrix will be read in row by row. The other operators to overload are as follows:
    
!transpose of the matrix
If matrix T is the transpose of matrix A, the value at position T[i][j] = A[j][i]. The dimensions of A and T will be exactly opposite. That is, the number of rows in A will equal the number of columns in T and the number of columns in A will equal the number of rows in T.
*matrix multiplication (the cross product)
When multiplying matrices A and B, the dimensions must be exactly opposite. That is, the number of rows in A must equal the number of columns in B and the number of columns in A must equal the number of rows in B. If matrix R is the result of adding A and B, the value at R[i][j] = Sum of (A[i][1]*B[1][j] + A[i][2]*B[2][j] + ... + A[i][m]*B[m][j]), where m is the number of columns in A. Note the A*B is not the same as B*A.
+matrix addition
When adding matrices A and B, the dimensions must be the same. That is the number of rows in A must equal the number of rows in B and the number of columns in A must equal the number of columns in B. If matrix R is the result of adding A and B, the value at R[i][j] = A[i][j] + B[i][j].
*scalar multiplication (the dot product)
This is when a singular value will be multiplied by a matrix or a matrix will be multiplied by a singular. The resulting matrix R will have the same dimensions as the original matrix A and R[i][j] = value*A[i][j].
=assignment
The left-hand side is to be made to be an exact copy of the right-hand side. Make sure the assignment operation deallocates any dynamic memory that had been allocated to the left-hand side matrix.
==equality
For two matrices A and B to be equal, they must have the same dimensions and A[i][j] must equal B[i][j] for all possible combinations of i and j.
!=inequality
Two matrices A and B are not equal if they have different dimensions or A[i][j] is not equal to B[i][j] for any combination of i and j.
The overloaded operator * will perform two different operations based on the type of the operands. If both operands are of type Matrix, then matrix multiplication will be performed. If one operand is of type Unum and the other is of type Matrix, then scalar multiplication will be performed. For the matrix multiplication and addition, the code must validate the two matrices are of compatable dimensions to perform the operation. If they are not of compatable dimensions, print an error message.

The class is to have a method access() that is to return the reference to a position in the matrix. This method will take two integer parameters that correspond to the row and column of the position in the matrix. This method is to be used for both storage and retrieval of values in the matrix. This method should print an error message if either integer parameter is out of range.

The class is to have a constructor that takes a null terminated character array that will be the name of a file. This file will contain the input needed to initialize a matrix. The class is to have another constructor that takes two integer values. These values indicate the number of rows and columns in the matrix. All values in the matrix are to be initialized to zero. Write any other constructors, destructor or methods that you feel are necessary.

Your program must be written in good programming style. This includes (but is not limited to) meaningful identifier names, a file header at the beginning of each source code file, a function header at the beginning of the function, proper use of blank lines and indentation to aide in the reading of your code, explanatory "value-added" in-line comments, etc.

The work you turn in must be 100% your own. You are not allowed to share code with any other person (inside this class or not). You may discuss the project with other persons; however, you may not show any code you write to another person nor may you look at any other person's written code.

You are also to write a one to two page program description. This write up must be submitted with your program and be in ASCII text format. This description is to explain your internal data structures, code structures and the algorithms used in your program. Remember, this program description will be read by another student when the critiques are done for this assignment. Often the title of "readme" is used for these types of documents.

You are to submit this project using the EECS Department's UNIX machine's turnin command. The project name for this assignment is mp3. Be sure to submit all source code and header files as well as your makefile and program description. Failure to turnin all required pieces will result in a lower grade for the assignment.