CIS 3020 Project 2

From In The Wings
Jump to navigation Jump to search

Background

In this assignment you will perform basic arithmetic operations with rational numbers (x/y). Many fractional numbers cannot be represented exactly. For example, the value 1/3 as a real number is 0.333333333... At some point we must stop writing 3s, which results in a roundoff error. A similar problem exists with many fraction numbers inside a computer. To alleviate this problem, we can represent these numbers as rationals. A rational number maintains the numerator and denominator as separate integer values, never performing the division. Since integers are represented exactly, no roundoff errors occur.

In this assignment you are to implement the basic arithmetic operations of addition, subtraction, multiplication, and division. The output of the operations must also be in the form of a rational number. The operations are performed as illustrated below:

Addition

 x1     x2     (x1*y2) + (x2*y1)
---- + ---- = -------------------
 y1     y2          (y1*y2)

For example:

1/2 + 2/3 = 7/6

Subtraction

 x1     x2     (x1*y2) - (x2*y1)
---- - ---- = ------------------
 y1     y2          (y1*y2)

For example:

2/3 - 1/2 = 1/6

Multiplication

 x1     x2     (x1*x2)
---- * ---- = ---------
 y1     y2     (y1*y2)

For example:

1/2 * 2/3 = 2/6

Division

 x1     x2     (x1*y2)
---- / ---- = ---------
 y1     y2     (y1*x2)

For example:

1/2 / 2/3 = 3/4

RationalNumber.java

public class RationalNumber {
  // Instance data members

  private int numerator;
  private int denominator;

  //
  // Public Instance Methods
  //

  //
  // Accessors
  //

  // This method returns the numerator value of the rational number
  public int getNumerator() {
    return numerator;
  } // End getNumerator

  // This method returns the denominator value of the rational number
  public int getDenominator() {
    return denominator;
  } // End getDenominator

  /* This method overrides the default toString() method and returns the
     String representation of the rational number object in the x/y format.
  */
  public String toString() {
    return numerator + "/" + denominator; /* Seems silly to create a new
                                             string variable just to return
                                             this value */
  } // End toString

  /* This method calls the appropriate operation based on the value of
     the operation perameter. operation can have as a value "add", "sub",
     "mult", or "div". Any other value for operation will cause the program
     to print an error message to the standard output (monitor). This method
     returns the resulting rational number object and also prints this number
     to the standard output (NOTE: it only prints the number - it does not
     print anything else). If a bad operation is given, it should return and
     print the rational number 0/0.

     Note that all of the operations that this method calls are private to
     the class, so they cannot be called from outside. This also means less
     methods to actually test from a driver class because they will not be
     accessible from that driver class.
  */
  public String perform(String operation, RationalNumber rn) {
    String answer = "0/0";
    // Use operators to ensure first that operation is valid
    if ((operation == "add") || (operation == "sub") || (operation == "mult")
                                || (operation == "div")) {
      // Alright, we know what operation to perform, now let's check to
      // ensure that it can legally be done. If either denominator is
      // zero, then we have a problem...
      if((this.getDenominator() != 0) && (rn.getDenominator() != 0)) {
        /* This checks to see that both denominators have SOMETHING in them
           other than zero. Even negative numbers would work in this case */

        // Now that we know it is valid, we can test it against each possible
        // value and perform the proper operation
        if(operation == "add") {
          answer=this.addRational(rn); /* Add the two rational numbers
                                          together. */
        } else if (operation == "sub") {
          answer=this.subRational(rn); // Subtract the two rational numbers.
        } else if (operation == "mult") {
          answer=this.multRational(rn); // Multiply the two rational numbers.
        } else if (operation == "div") { /* We have to check to make sure that
                                            the numerator of rn is not zero as
                                            either, as that would be a
                                            division by zero error! */
          if (rn.getNumerator() != 0) {
            answer=this.divRational(rn); // Divide the two rational numbers.
          } else {
            answer="0/0 - Divide by ZERO!";
          }
        } else { /* If we get to this point, something very wrong has happened
                    because the initial IF-THEN statement failed to detect
                    that this value came through. It should NEVER get to this
                    point in this particular IF-THEN tree. */
          System.out.print("Something very wrong has happened.\n");
          System.out.printf("Variable operation had value %s.\n", operation);
        } // End if
      } // End if
    } else { /* Input operation was NOT a valid operation. We then return
                the rational number of 0/0 because that is what is required
                by the program specification.
             */
      answer="0/0";
    } // End IF-ELSE
    //    System.out.printf("%d/%d",numerator,denominator);
    return answer;
  } // End perform

  //
  // Private Instance Methods
  //

  /* This method adds the current rational number (the one receiving this
     message) object with rn and returns the resulting RationalNumber object.
  */
  private String addRational(RationalNumber rn) {
    // Get our values and put them into local variables.
    int x1 = this.getNumerator();
    int x2 = rn.getNumerator();
    int y1 = this.getDenominator();
    int y2 = rn.getDenominator();
    // First, let's find out if we even need to bother with cross
    // multiplying. If the denominators of both rational numbers
    // are equal, there is no point in cross-multiplying... we can
    // just add.
    if (y1 != y2) {
      // Cross multiply to get our bases equal
      x1 = x1 * y2;
      x2 = x2 * y1;
      // Now set our denominator to the multiplied version
      y1 = y1 * y2;
    } /* End if -- If this came out as false, then we should be able
         to just fall through and go on with adding the numerators
         together. */

    // Now add the two together numerators together
    x1 = x1+x2;
    /* At this point, we have the following:
       x1y2 + x2y1
       -----------
          y1y2

       And this is represented in our variables now as:
       x1
       --
       y1

       This happens to be our answer, as it appears that we do not have to
       reduce to lowest common denominator. All we have to do now is print
       out the answer. We don't want to set anything because we may want
       to use these objects again.
    */

    // Now, let's make sure that both the numerator and denominator are not
    // both negative. That just looks silly!
    if ((x1<0) && (y1<0)) {
      x1=-x1;
      y1=-y1;
    }
    // And, because I like things to look like normal fractions, let's make
    // sure that if the Rational number is negative, that the negative sign
    // is in the numerator and not the denominator...
    if((x1>0) && (y1<0)) {
      x1=-x1;
      y1=-y1;
    }

    return x1 + "/" + y1;
  } // End addRational

  /* This method subtracts the current rational number (the one receiving this
     message) object with rn and returns the resulting RationalNumber object
  */

  private String subRational(RationalNumber rn) {
    String ret_value;
    // Let's be clever... instead of doing all of the annoying stuff
    // like we did in the addRational number, why don't we just
    // temporarily set the numerator of this object to a negative value (or
    // positive if it is already negative), call the add routine, then
    // set it back to its original value?
    //
    // Originally when I wrote this, I changed the values of rn instead
    // of the local variables. Then I realized that actually takes more
    // processing power than to simply change the local variables, so I
    // changed it to mess with the local variables instead. Then I tested
    // it out, and realized just WHY I had done it using the rn object
    // for this one. If you change the numerator to negative on this one,
    // you get the reverse answer of what you were trying to get. This
    // is obviously bad.
    rn.setNumerator(-rn.getNumerator());
    ret_value = this.addRational(rn);
    rn.setNumerator(-rn.getNumerator());
    return ret_value;
  } // End subRational

  /* This method multiplies the current rational number (the one receiving this
     message) object with rn and returns the resulting RationalNumber object
  */
  private String multRational(RationalNumber rn) {
    // Get our values and put them into local variables.
    int x1 = this.getNumerator();
    int x2 = rn.getNumerator();
    int y1 = this.getDenominator();
    int y2 = rn.getDenominator();
    /*  All we have to do for multiplication is multiply the numerators and
        denominators and we have the answer.
    */
    x1 = x1 * x2;
    y1 = y1 * y2;

    // Now, let's make sure that both the numerator and denominator are not
    // both negative. That just looks silly!
    if ((x1<0) && (y1<0)) {
      x1=-x1;
      y1=-y1;
    }
    // And, because I like things to look like normal fractions, let's make
    // sure that if the Rational number is negative, that the negative sign
    // is in the numerator and not the denominator...
    if((x1>0) && (y1<0)) {
      x1=-x1;
      y1=-y1;
    }

    // Poof! All done, now we just print it out using our generic printing
    // routine.
    return x1 + "/" + y1;
  } // End multRational

  /* This method divides the current rational number (the one receiving this
     message) object with rn and returns the resulting RationalNumber object
  */
  private String divRational(RationalNumber rn) {
    /* Since we got clever with subRational, let's do the same with
       this one as well... */
    int hold; /* Holding variable for when we swap the numerator and
                 denominator of this object */
    String ret_value;
    hold = numerator;
    numerator = denominator;
    denominator = hold;
    // We have swapped the numerator and denominator for this object
    ret_value = this.multRational(rn);
    // We now have the two multiplied
    hold = numerator;
    numerator = denominator;
    denominator = hold;
    // We have now swapped back the numerator and denominator of this object
    return ret_value;
  } // End divRational

  //
  // Constructors
  //

  // Not sure how this was missed in the specifications, but we need to be
  // able to set the numerator and denominator somehow. I am not going to
  // allow the actual variables to be seen, so I have to write some methods
  // that will do it instead.
  public void setNumerator(int numerator) {
    this.numerator=numerator;
  } // End setNumerator

  public void setDenominator(int denominator) {
    if (denominator != 0) { /* Check to ensure that we are not setting the
                               denominator to zero. If we did, that would
                               be a divide by zero error. */
      this.denominator=denominator;
    } else { // Bad user! No cookie!
      System.out.print("Error! Cannot set denominator of a number to 0! " +
                       "Leaving value as it was set before.\n");
    }
  } // End setDenominator

} // End Class RationalNumber

RationalNumberDemo.java

public class RationalNumberDemo extends RationalNumber {
  public static void main(String[] arg) {
    /* The first thing we need to do is create our two objects. We do that
       by first creating the two new objects, then setting the rational
       numbers that they represent.
    */
    RationalNumber ratNum1 = new RationalNumber();
    RationalNumber ratNum2 = new RationalNumber();
    // Now set the first one's value. Note that this is where we would
    // set all of the values needed. This is the ONLY place we need to
    // set them!
    ratNum1.setNumerator(2);
    ratNum1.setDenominator(5);
    // And the second one's...
    ratNum2.setNumerator(1);
    ratNum2.setDenominator(7);
    //
    // Now we need to go and see that these two numbers really were
    // put in properly...
    //
    System.out.printf("Rational Number 1, rn1, has been defined to be: %s\n",
                      ratNum1.toString());
    System.out.printf("Rational Number 2, rn2, has been defined to be: %s\n",
                      ratNum2.toString());
    /* Now we need to print out the different variations of the operations
       that can be performed on these two rational numbers. Because we have
       defined them above, we are not going to type in those numbers again
       here. By defining them up there, we can now just call on those
       definitions from now on and not have to worry about changing them in
       more than the one place above.

       In the future, we would probably have them either input by the user
       from the command line or pop up an input box for them to be entered
       into, thus making them more dynamic. As it is, it is very easy to
       take the RationalNumber class and use it in such a front end.
    */

    // Add the second one to the first one
    System.out.printf("%s + %s = %s\n", ratNum1.toString(),
                      ratNum2.toString(), ratNum1.perform("add", ratNum2));
    // Subtract the second one from the first one
    System.out.printf("%s - %s = %s\n", ratNum1.toString(), ratNum2.toString(),
                      ratNum1.perform("sub", ratNum2));
    // Subtract the first one from the second one
    System.out.printf("%s - %s = %s\n", ratNum2.toString(), ratNum1.toString(),
                      ratNum2.perform("sub", ratNum1));
    // Multiply the first one by the second one
    System.out.printf("%s * %s = %s\n", ratNum1.toString(), ratNum2.toString(),
                      ratNum1.perform("mult", ratNum2));
    // Divide the first one by the second one
    System.out.printf("%s / %s = %s\n", ratNum1.toString(), ratNum2.toString(),
                      ratNum1.perform("div", ratNum2));
    // Divide the second one by the first one
    System.out.printf("%s / %s = %s\n", ratNum2.toString(), ratNum1.toString(),
                      ratNum2.perform("div", ratNum1));
  } // End main
} // End RationalNumberDemo Class