Difference between revisions of "CIS 3020 Project 2"

From In The Wings
Jump to navigation Jump to search
 
Line 51: Line 51:
 
1/2 / 2/3 = 3/4
 
1/2 / 2/3 = 3/4
 
</pre>
 
</pre>
 +
==RationalNumber.java==
 +
<pre>
 +
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
 +
</pre>
 +
==RationalNumberDemo.java==

Revision as of 10:53, 30 March 2007

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