CSCI 15 Assignment #3, introduction to classes/objects. 100 points, due 10/21/13

A mixed expression is an expression of the form a + b/c, where a, b, and c are integers, b >= 0 and c > 0. By convention, b/c is always non-negative, and has the property that 0 <= (b/c) < 1. Also, b/c is always shown in reduced form, or as 0 / 1.

Implement the MixedExpression class, allowing use of the mixed expression as an abstract data type. Also, write a calculator client to drive the MixedExpression class. Your MixedExpression class must be described in a header file (mixedexpression.h) and implemented in a separate library source file (mixedexpression.cpp), both of which are in the same working directory as the client calculator program. The client code will #include the header you wrote, and will be linked with the class library object file. Create a project for the 2 source files.

Your MixedExpression class must provide public member functions (methods) to add, subtract, multiply and divide mixed expressions. These must have the form:

MixedExpression MixedExpression::add( MixedExpression op )

This will add "this" mixed expression (e.g., "self" – the addend) to the argument op , the augend (remember, addend + augend yields sum) and return the sum. The other methods; subtract(), multiply(), and divide(), will also take a mixed expression (the argument) and treat it as the right hand operand of their appropriate operation, using self (the object to the left of the '.') as the left hand side operand. All of these functions will create a new MixedExpression, set its values, and return it so it can be assigned to the variable holding the result.

Given MixedExpression variables res, op1 and op2, the call in the calculator code will look like this:

res = op1.add( op2 );

You must also provide appropriate constructors, observers (i.e., to print a mixed expression, in the form (a + b / c), where parentheses and spaces are required), and manipulators (i.e., to take supplied values and set them into the mixed expression).

Your class data members (long a, b and c) must be private.

YOU MAY NOT ADD ANY OTHER DATA MEMBERS TO THE CLASS.

YOU MAY NOT ADD ANY OTHER PARAMETERS TO THE METHODS.

You may need private "helper" functions, for example, a private method reduce() to convert a mixed expression to its "normal" form.

Your program will read lines of text in the form
( a + b / c ) <operator> ( d + e / f )

where the parentheses ( ), the +, and the / are literals, <operator>  {+, -, *, /}, and a, b, c, d, e and f are signed integers.

Your input method, ReadMixedExp( istream &in ) is a method of the class MixedExpression, and extract the object's data values from input. Your client will call this twice per line of input, once for each operand. The parameter type istream & means the method can take either an istream or an ifstream as an argument.

Your client must extract the operator itself (a mixed expression doesn't understand math) between extracting the operands. The client must interpret the operator itself.

You may assume the input is correctly formatted. Use an input file and process one line at a time until you reach end-of-file. Output is to a text file. Pass the file names into the program via the command line. Print the entered line (converted to reduced normal form if needed), followed by =, then the result.

The operands and the result must print themselves. That is, you must use a method printData( ostream &out ) {which can take either an ostream or an ofstream} to print the mixed expression.

For example, with this input line

( 1 + 2 / 6 ) + ( 3 + -3 / 9 )

The corresponding output would be (notice changes from the input form to reduced normal form)

( 1 + 1 / 3 ) + ( 2 + 2 / 3 ) = ( 4 + 0 / 1 )

This spacing and format of the input and output lines is required.

Test your program with several sets of data, including attempts at illegal data or operations, such as
( 1+ 0/1 ) / ( 0 + 0/1 )

Your program must catch and appropriately handle undefined expressions such as 1+1/0. Just use the value 0+0/1 in these cases. Later, we'll see how to really handle these errors.

Here is my source code for the header file (MixedExpression.h):

#ifndef MIXEDEXPRESSION_H
#define MIXEDEXPRESSION_H
#include<fstream>
using namespace std;

class MixedExpression
{
    private:
        long a, b, c; // Variables of the mixed expression.
        long GCD(long, long); // Get the greatest common divisor.
        void reduce(void); // Reduce a mixed expression to its normal form.
    public:
        MixedExpression(); // Default constructor of the mixed expression class.
        MixedExpression(long, long, long);
        MixedExpression add(MixedExpression op); // Add two numbers.
        MixedExpression subtract(MixedExpression op); // Subtract two numbers.
        MixedExpression multiply(MixedExpression op); // Multiply two numbers.
        MixedExpression divide(MixedExpression op); // Divide two numbers.
        void ReadMixedExp(istream &in); // Read each line.
        void printData(ostream &out); // Print the result.
};
#endif

Here is my source code for the library source file (MixedExpression.cpp):

#include "MixedExpression.h"
#include<iostream>
#include<fstream>
using namespace std;

long GCD(long x, long y) // Get the greatest common divisor.
{
    long remainder; // Holds the remainder.
    while(y != 0)
    {
        // Get the value of the remainder by dividing y by x.
        remainder = x % y;
        x = y;
        y = remainder;
    }
    // Return the greatest common divisor.
    return x; 
}
// Convert a mixed expression to its normal form.
void reduce(void)
{
    long a, b, c, x;
    long gcd;
    x = (a*c)+b;
    gcd = GCD(x, c);
    x /= gcd;
    c /= gcd;
}

// Set three values in the default constructor to 0.
MixedExpression::MixedExpression()
{
    a = 0;
    b = 0;
    c = 1;
}

MixedExpression::MixedExpression(long d, long e, long f)
{
    d = a;
    e = b;
    f = c;
}

// Add two values and return the sum.
MixedExpression MixedExpression::add(MixedExpression op)
{
    MixedExpression res;
    res.a = (((*this).a * (*this).c) + (*this).b)/(*this).c
            + ((op.a * op.c) + op.b)/op.c;
    return res;
}

// Subtract two values and return the difference.
MixedExpression MixedExpression::subtract(MixedExpression op)
{
    MixedExpression res;
    res.a = (((*this).a * (*this).c) + (*this).b)/(*this).c
            - ((op.a * op.c) + op.b)/op.c;
    return res;
}

// Multiply two values and return the product.
MixedExpression MixedExpression::multiply(MixedExpression op)
{
    MixedExpression res;
    res.a = (((*this).a * (*this).c) + (*this).b)/(*this).c
            * ((op.a * op.c) + op.b)/op.c;
    return res;
}

// Divide two values and return the quotient.
MixedExpression MixedExpression::divide(MixedExpression op)
{
    MixedExpression res;
    res.a = (((*this).a * (*this).c) + (*this).b)/(*this).c
            / ((op.a * op.c) + op.b)/op.c;
    return res;
}

// Read each value while not at the end of the file.
void MixedExpression::ReadMixedExp(istream &in)
{
    a = 0;
    b = 0;
    c = 0;
    while(!in.eof())
    {
        in >> a >> b >> c;
    }
}

// Print the results.
void MixedExpression::printData(ostream &out)
{
    out << "(" << a << "+" << b << "/" << c << ")" << flush;
}

Here is my source code for the calculator client (Calculator.cpp):

#include "MixedExpression.h"
#include<iostream>
#include<fstream>
using namespace std;

int main(int argc, char *argv[])
{
    MixedExpression res;
    MixedExpression op1;
    MixedExpression op2;
    int symbol;
    long x,y;
    ifstream in;
    ofstream out;
    char input[12] = "numbers.txt";
    char output[15] = "num result.txt";
    //argv[1] = "numbers.txt";
    //argv[2] = "num result.txt";

    // Prompt for the file name.
    cout << "Enter the file name: ";
    cin >> input;

    // Open the input file.
    in.open(input);
    // Open the output file.
    out.open(output);

    /*if( argc == 3 ) 
    {
        input = argv[1];
        output = argv[2];
    }
    else 
    {
        return 1;
    }*/

    if(in)
    {
        res.ReadMixedExp(in);
        while(!in.eof())
        {
            res.ReadMixedExp(in);
            switch(symbol)
            {
                case '+': res = op1.add(op2); // Get the sum.
                    break;
                case '-': res = op1.subtract(op2); // Get the difference.
                    break;
                case '*': res = op1.multiply(op2); // Get the product.
                    break;
                case '/': res = op1.divide(op2); // Get the quotient.
                    break;
            }
            res.printData(out);
        }
        res.printData(out);
    }
    // Print the result.
    res.printData(out);
    // Close the input file.
    in.close();
    // Close the output file.
    out.close();

    return 0;
}

My program is not printing any output. I'm not sure what I am doing incorrectly. I made several adjustments to my codes and I'm still not getting any output. Is there anything I need to change in my three files?

andrew.mendonca.967
Deleted Member

So firstly you need to have an idea of what you expect your program to output, you haven't told us so it is rather hard for us to guess.

Secondly if the program is not performing as expected you need to find where the bug is, you could try examining the code but frankly if you haven't already seen it then you are unlikely to spot it now and without having the input data and the expected output I have no clues to go on as to where to look in your code to find an error and I don't care to examine each line of this much code.

That leaves you will tracing through the code to find the problem, you have 2 options here

  1. Us a symbolic debugger, this is a special program, you compile your program in debug mode and run it in the debugger and this allows you to examine the code as it is running including the values of variables and stack trace and memory contents etc.
  2. A poor second is to add additional output (cout) statements to trace the execution path of the program and value of variables. Although a poor second in a small program or localised piece of code this can be plenty.

Things that stand out as errors

  • The implementation of reduce acts only on local unitialised data and does not change the state of the instance it is operating on.
  • in main op1 and op2 are never set
  • in main it looks like you read res more times that is likely to be good, expecially since you generally overwrite the value read.

If you are going to try method 2 start by outputing the values in your loop in main and the values read in MixedExpression::ReadMixedExp

MixedExpression.cpp.
Look at line 94 bout printdata method. The logic is not right.
You seem to read data to out output file object but not printing to screen. check your logic and debug well.

It seems to me, your most immediate problem, is not giving symbol a value. Without this the switch block never executes any case statements.

Also your ReadMixedExp doesn't skip non numbers when reading the file.

Edited 3 Years Ago by tinstaafl

This question has already been answered. Start a new discussion instead.