Jump to content

First Post! Objects and Classes Question

- - - - -

This topic has been archived. This means that you cannot reply to this topic.
1 reply to this topic

#1
stuckey

stuckey

    Newbie

  • Members
  • Pip
  • 1 posts
Hello,

I'm currently teaching myself java from the "Art and Science of Java" by Eric Roberts. On pg. 220 there's an exercise that says:

Quote

The implementation of the Rational class given in this chapter is not particularly useful in practice because it doesn't allow the numerator and denominator to exceed the size of an integer, even though larger values tend to occur quite often in rational arithmetic. One way to avoid the problem is to use the BigInteger class in that java.math package, which defines an extended type of integer that can take on arbitrarily large values. Rewrite the implementation of Rational so that the private instance variables num and den are declared as BigIntegers instead of ints, but without changing the argument and result types of any of the public methods. To learn how BigInteger works, you can consult the javadoc page

Here is the code for the original Rational class:

/** Rational class does... 
 * 
 * @author J. STUCKEY
 *
 */

public class Rational {

/** Crates a new Rational initialized to zero. */ 
	public Rational() {
		this(0);
	}
/** 
 * Creates a new Rational from ... 
 * @param n The initial value
 */
	public Rational (int n) {
		this(n,1);
	}
/** 
 * Creates a new Rational with the value x / y.
 * @param x The numerator of the rational number
 * @param y The denominator of the rational number
 */
	
	public Rational(int x, int y) {
		int g = gcd(Math.abs(x), Math.abs(y));
		num = x /g;
		den = Math.abs(y) / g;
		if (y < 0) num = -num;
	}
/**
 * Adds the rational number r to this one and returns the sum.
 * @param r the rational number to be added
 * @return The sum of the current number and r 	
 */
	public Rational add(Rational r) {
		return new Rational(this.num * r.den + r.num * this.den, this.den * r.den);
	}
/** 
 * Subtraction
 * @param r The rational number to be subtracted
 * @return The result of subtracting r from the current number
 */
	public Rational subtract(Rational r) {
		return new Rational(this.num * r.den - r.num * this.den, this.den * r.den);
	}
/** 
 * Multiply
 * @param r The rational number used as a multiplier
 * @return The result of multiplying the current number by r
 */
	public Rational multiply(Rational r) {
		return new Rational(this.num * r.num, this.den * r.den);
	}

/** 
 * Divides 
 * @param r The number
 * @return The result of dividing 
 */
	public Rational divide(Rational r) {
		return new Rational(this.num * r.den, this.den * r.num);
		}
/** 
 * Creates a string representation of this rational number.
 * @return The string representation of this rational number
 */

	public String toString() {
		if (den == 1) {
			return "" + num;
		} else {
			return num + "/" + den;
		}
	}
/**
 * Calculates the greatest common divisor using Euclid's algorithm.
 * @param x First int
 * @param y Second int
 * @return The greatest common divisor of x and y
 */

	private int gcd(int x, int y) {
		int r = x % y;
		while (r != 0) {
			x = y; 
			y = r; 
			r = x % y;
		}
			return y;
	} 

	/* Private Instance Variables */ 
	private int num; 
	private int den; 
}

And what I have changed so far:
import java.math.BigInteger;

/** Rational class does... 
 * 
 * @author J. STUCKEY
 *
 */

public class Rational {

/** Crates a new Rational initialized to zero. */ 
	public Rational() {
		this(0);
	}
/** 
 * Creates a new Rational from ... 
 * @param n The initial value
 */
	public Rational (int n) {
		this(n,1);
	}
/** 
 * Creates a new Rational with the value x / y.
 * @param x The numerator of the rational number
 * @param y The denominator of the rational number
 */
	      public Rational(int x, int y) //I don't really understand this
	      {
	          BigInteger x1 = BigInteger.valueOf(x);
	          BigInteger y1 = BigInteger.valueOf(y);
	          BigInteger g = x1.gcd(y1);
	          num = x1.divide(g);
	          den = y1.abs().divide(g);
	          if (y1.compareTo(BigInteger.valueOf(0)) < 0)
	             num = num.negate();
	      }

	//public Rational(int x, int y) {
	//int g = gcd(Math.abs(x), Math.abs(y));
	//	num = x /g;
	//	den = Math.abs(y) / g;
	//	if (y < 0) num = -num;
	//}
/**
 * Adds the rational number r to this one and returns the sum.
 * @param r the rational number to be added
 * @return The sum of the current number and r 	
 */
	      
	public Rational add(Rational r) { //This is the new method that I don't know how to implement
		return new Rational(BigInteger.multiply(this.num r.den);
	}
	public Rational add(Rational r) { //This is the old method
		return new Rational(this.num * r.den + r.num * this.den, this.den * r.den);
	}
/** 
 * Subtraction
 * @param r The rational number to be subtracted
 * @return The result of subtracting r from the current number
 */
	public Rational subtract(Rational r) {
		return new Rational(this.num * r.den - r.num * this.den, this.den * r.den);
	}
/** 
 * Multiply
 * @param r The rational number used as a multiplier
 * @return The result of multiplying the current number by r
 */
	public Rational multiply(Rational r) {
		return new Rational(this.num * r.num, this.den * r.den);
	}

/** 
 * Divides 
 * @param r The number
 * @return The result of dividing 
 */
	public Rational divide(Rational r) {
		return new Rational(this.num * r.den, this.den * r.num);
		}
/** 
 * Creates a string representation of this rational number.
 * @return The string representation of this rational number
 */

	public String toString() {
		if (den == 1) {
			return "" + num;
		} else {
			return num + "/" + den;
		}
	}
/**
 * Calculates the greatest common divisor using Euclid's algorithm.
 * @param x First int
 * @param y Second int
 * @return The greatest common divisor of x and y
 */

	private int gcd(int x, int y) {
		int r = x % y;
		while (r != 0) {
			x = y; 
			y = r; 
			r = x % y;
		}
			return y;
	} 

	/* Private Instance Variables */ 
	private BigInteger num; 
	private BigInteger den; 
}

I found a post somewhere with the code for the constructor, but unfortunately I don't really understand what is going on there. I've been staring at the screen for fifteen minutes trying to think of how to implement the methods. I have no idea how to implement this and re-reading the chapter has offered no help. The book does not explain enough for one to understand how to do this. I would much appreciate it if someone could give me a push in the right direction and explain to me what is going on. Please do not give code without explanations.

#2
bobdark

bobdark

    Programmer

  • Members
  • PipPipPipPip
  • 164 posts
public Rational(int x, int y) //I don't really understand this
	      {
	          BigInteger x1 = BigInteger.valueOf(x);
	          BigInteger y1 = BigInteger.valueOf(y);
As stated above, the problem with using int was that numenator and denomenator
could not represent values larger than the maximum value that and integer may represent.
So the idea is to use BigInteger instead of int, to represent numenator and denomenator values,
which can represent larger range of values.
Notice that the range of values representable by int, is a sub-range of all the value representable by BigInt
(makes sense, no?) So this is why there is a method that creates new BigInteger object which would represent
a given int value. This what happens above.
BigInteger g = x1.gcd(y1);
	          num = x1.divide(g);
	          den = y1.abs().divide(g);
Here we force the rational number to be represented by minimal possible values of
numenator and denomenator. g=x1.gcd(y1) means take object x1 and y1 and find their greatest common
divisor. The thing is that the gcd method used here is defined in the BigInt class, which means
that it finds the greatest common divisor of the value that specific BigInt object represents
and the passed parameter. The result is also a BigInt and not int because
you cannot assume anything about the result except that it can be represented by BigInt.
den = y1.abs().divide(g) means take the absolute value of y and divide it by
the greatest common divisor. The absolute value of y is taken here for the sake of simplicity
and order of actions. The case whether the number is positive/negative is taken care of
in the next lines:
 if (y1.compareTo(BigInteger.valueOf(0)) < 0)
	             num = num.negate();
	      }
What they do here is they check whether y1 is smaller than 0, i.e. negative.
compareTo is also a method of BigInt class and it accepts an argument and returns true/false
indicating whether the argument is bigger/smaller than the value represented by that object.
They use BigInteger.valueOf(0) in order to pass to the compareTo method an argument of type
BigInteger. valueOf is a static method of BigInteger class and it returns a
BigInteger object representing the value given as the argument.
y1.compareTo(BigInteger(0)) would produce the same result.
In the end they call the negate method if y1 was indeed smaller than 0.
As you can probably guess, negate "multiplies by -1" - it returns the negative value of the represented number.

Well that is it, hope it helped.