Problem For this programming assignment, you are to complete the Fraction class
ID: 667929 • Letter: P
Question
Problem
For this programming assignment, you are to complete the Fraction class discussed in class and the provided partial test driver (both given below) for testing your class.
Modifications to Make
Modify setters so that they ignore inappropriate values (i.e., divide by zero)
Implement the equals() method inherited from the top-level Object class
Implement less than and greater than methods
Implement add, subtract, and multiply methods
Complete the test driver for your Fraction class to test the newly-added methods.
FRACTION CLASS
public class Fraction {
private int numer;
private int denom;
public Fraction() { // no-arg constructor
numer = 0;
denom = 1;
}
public Fraction(int numer, int denom) {
this.numer = numer;
this.denom = denom;
}
public Fraction(Fraction frac) { // copy constructor
numer = frac.getNumer();
denom = frac.getDenom();
}
// getters and setters
public int getNumer() {
return numer;
}
public void setNumer(int x) {
numer = x;
}
public int getDenom() {
return denom;
}
public void setDenom(int x) {
denom = x;
}
// Special Methods
public String toString() {
return numer + "/" + denom;
}
// Other Methods
public Fraction reduce() {
Fraction temp = new Fraction();
int GCD = gcd(numer, denom);
temp.setNumer(numer / GCD);
temp.setDenom(denom / GCD);
return temp;
}
// Private Methods
private int gcd(int n1, int n2)
{
int M, N, R;
if (n1 < n2)
{
N = n1;
M = n2;
}
else
{
N = n2;
M = n1;
}
R = M % N;
while (R != 0)
{
M = N;
N = R;
R = M % N;
}
return N;
}
}
FRACTION CLASS TEST DRIVER
public class FractionClassTestDriver {
public static void main(String[] args) {
// test constructors
Fraction frac0 = new Fraction();
System.out.println("TESTING NO-ARG CONSTRUCTOR");
System.out.println(“frac0: Result should be 0/1:”);
System.out.println("Numer = " + frac0.getNumer());
System.out.println("Denom = " + frac0.getDenom());
System.out.println("TESTING int/int CONSTRUCTOR");
Fraction frac1 = new Fraction(2,4);
System.out.println(“frac1: Result should be 2/4:”);
System.out.println("Numer = " + frac1.getNumer());
System.out.println("Denom = " + frac1.getDenom());
System.out.println("TESTING Fraction CONSTRUCTOR");
Fraction frac2 = new Fraction(frac1);
System.out.println(“frac2: Result should be 2/4:”);
System.out.println("Numer = " + frac2.getNumer());
System.out.println("Denom = " + frac2.getDenom());
System.out.println("TESTING COPY CONSTRUCTOR frac1 à frac2");
if (frac1.getNumer() == frac2.getNumer() &&
frac1.getDenom() == frac2.getDenom() &&
frac1 != frac2)
{
System.out.println("Copy constructor working");
}
else
System.out.println("PROBLEM with copy constructor");
// test equal method
System.out.println("TESTING EQUALITY OF frac1 and frac2 -");
System.out.println("SHOULD BE FOUND EQUAL:");
if (frac1.equals(frac2))
{
System.out.println("frac1 and frac2 found equal");
}
else
{
System.out.println("frac1 and frac2 NOT equal");
}
// test reduce method
System.out.println("TESTING reduce METHOD ON frac1");
Fraction reduced_frac1 = frac1.reduce();
System.out.println("Reduced frac1 = " + reduced_frac1);
// test getters and setters
frac2.setNumer(8);
frac2.setDenom(12);
System.out.println("Numer = " + frac2.getNumer());
System.out.println("Denom = " + frac2.getDenom());
// System.out.println("GCD of 2/4 = " + frac1.gcd(1,4));
}
* TO BE COMPLETED *
}
Explanation / Answer
Fraction.java
import java.math.BigInteger;
public class Fraction {
private int m_numerator;
private int m_denominator;
public static final Fraction ZERO_FRACTION = new
Fraction(0, 1);
public Fraction(int numerator, int denominator) throws
ArithmeticException {
setNumerator(numerator);
setDenominator(denominator);
}
public int getNumerator() {
return m_numerator;
}
private void setNumerator(int numerator) {
this.m_numerator = numerator;
}
public int getDenominator() {
return m_denominator;
}
private void setDenominator(int denominator) {
if(0 == denominator) {
throw new ArithmeticException
("Fraction with a Zero denominator encountered !!!");
}
this.m_denominator = denominator;
}
public Fraction add(Fraction f) {
return additionSubtractionUtil(f, true);
}
public Fraction subtract(Fraction f) {
return additionSubtractionUtil(f, false);
}
public Fraction multiply(Fraction f) {
if (f == null) {
throw new IllegalArgumentException("Multiplying
with a null is not permitted !!!");
}
if(this.getNumerator() == 0 || f.getNumerator() == 0)
{
return ZERO_FRACTION;
}
// this is to make sure that the values will not
overflow unless they are supposed to
int gcd1 = getGCD(this.getNumerator(),
f.getDenominator());
int gcd2 = getGCD(f.getNumerator(),
this.getDenominator());
return getReducedFraction
(multiplyAndCheckOverflow(this.getNumerator
()/gcd1, f.getNumerator()/gcd2),
multiplyAndCheckOverflow(this.getDenominator
()/gcd2, f.getDenominator()/gcd1));
}
private Fraction getReducedFraction(int numerator, int
denominator) {
if (denominator == 0) {
throw new ArithmeticException("Fraction cannot
have a Zero denominator !!!");
}
if (numerator==0) {
return ZERO_FRACTION;
}
int gcd = getGCD(numerator, denominator);
numerator /= gcd;
denominator /= gcd;
return new Fraction(numerator, denominator);
}
public Fraction divide(Fraction f) {
if (f == null) {
throw new IllegalArgumentException("Division by a
Null Fraction is not permitted !!!");
}
if (f.getNumerator() == 0) {
throw new ArithmeticException("Divide By Zero
Fraction Exception !!!");
}
return multiply(f.invert());
}
public boolean equals(Fraction f) {
if(f instanceof Fraction) {
return compareTo(f) == 0 ? true :
false;
}
return false;
}
public boolean greaterThan(Fraction f) {
if(f == null) {
throw new IllegalArgumentException
("Greater than comparison cannot be done on a Null Fraction
!!!");
}
return compareTo(f) == 1 ? true : false;
}
public void display() {
System.out.println(this.getNumerator() + "/" +
this.getDenominator());
}
public boolean lessThan(Fraction f) {
if(f == null) {
throw new IllegalArgumentException
("Less Than comparison cannot be done on a Null Fraction
!!!");
}
return compareTo(f) == -1 ? true : false;
}
private Fraction invert() {
if (this.getNumerator() == 0) {
throw new ArithmeticException("Cannot invert a
Zero Fraction !!!");
}
if (this.getNumerator() == Integer.MIN_VALUE) {
throw new ArithmeticException("Inversion of
Integer.MIN_VALUE lead to Overflow error !!!");
}
if (this.getNumerator() < 0) {
return new Fraction(-this.getDenominator(), -
this.getNumerator());
} else {
return new Fraction(this.getDenominator(),
this.getNumerator());
}
}
private int compareTo(Fraction f) {
if (this == f) {
return 0;
}
if (this.getNumerator() == f.getNumerator() &&
this.getDenominator() ==
f.getDenominator()) {
return 0;
}
long v1 = (long) this.getNumerator() * (long)
f.getDenominator();
long v2 = (long) f.getNumerator() * (long)
this.getDenominator();
if (v1 == v2) {
return 0;
} else if (v1 < v2) {
return -1;
} else {
return 1;
}
}
private Fraction negate() {
if (this.getNumerator() == Integer.MIN_VALUE)
{
throw new ArithmeticException("Integer Minimum
Negation Overflow !!!");
}
return new Fraction(-this.getNumerator(),
this.getDenominator());
}
private Fraction additionSubtractionUtil(Fraction f,
boolean isAddition) {
if (null == f) {
throw new IllegalArgumentException("Cannot
add/subtract a Fraction !!!");
}
if (0 == f.getNumerator()) {
return this;
}
if (this.getNumerator() == 0) {
return isAddition ? f : f.negate();
}
int gcd1 = getGCD(this.getDenominator(),
f.getDenominator());
if (1 == gcd1) {
// If no possible gcd, we just multiply and
throw an exception in case of overflow
int v1 = multiplyAndCheckOverflow
(this.getNumerator(), f.getDenominator());
int v2 = multiplyAndCheckOverflow(f.getNumerator
(), this.getDenominator());
return new Fraction(
isAddition ?
addAndCheckOverflow(v1, v2) : subtractAndCheckOverflow(v1,
v2),
multiplyAndCheckOverflow(this.getDenominator(),
f.getDenominator())
);
}
// Keep this in mind to follow the next sequence of
actions
// (a/b)+(c/d) = (a*d+b*c)/(b*d) = [((a*d
+b*c)/gcd1)/gcd2]/[b*d/gcd1*gcd2]
// normalizing the value in numerator using gcd1
BigInteger v1 = BigInteger.valueOf(this.getNumerator
()).multiply(BigInteger.valueOf(f.getDenominator()/gcd1));
BigInteger v2 = BigInteger.valueOf(f.getNumerator
()).multiply(BigInteger.valueOf(this.getDenominator()/gcd1));
BigInteger num1 = isAddition ? v1.add(v2) :
v1.subtract(v2);
// further normalizing the numerator using next
possible gcd
int num1Mod = num1.mod(BigInteger.valueOf
(gcd1)).intValue();
int gcd2 = (num1Mod==0) ? gcd1 : getGCD(num1Mod,
gcd1);
// result is equal to (num1/gcd2) /
(first.denominator/gcd1)(second.denominator/gcd2)
BigInteger res = num1.divide(BigInteger.valueOf
(gcd2));
if (res.bitLength() > 31) {
throw new ArithmeticException("Multiplication
Overflow error !!!");
}
return new Fraction(res.intValue(),
multiplyAndCheckOverflow(
this.getDenominator() / gcd1,
f.getDenominator() / gcd2));
}
private int subtractAndCheckOverflow(int v1, int v2) {
long sub = ((long)v1)-((long)v2);
if (sub < Integer.MIN_VALUE ||
sub > Integer.MAX_VALUE) {
throw new ArithmeticException("Integer Subtraction
Overflow !!!");
}
return (int)sub;
}
private int addAndCheckOverflow(int v1, int v2) {
long add = ((long)v1)+((long)v2);
if (add < Integer.MIN_VALUE ||
add > Integer.MAX_VALUE) {
throw new ArithmeticException("Integer Addition
Overflow !!!");
}
return (int)add;
}
private int multiplyAndCheckOverflow(int v1, int v2)
throws ArithmeticException {
long mul = ((long)v1)*((long)v2);
if(mul < Integer.MIN_VALUE || mul >
Integer.MAX_VALUE) {
throw new ArithmeticException("Integer
Multiplication Overflow for { " + v1 + " } { " + v2 + " }");
}
return (int)mul;
}
private int getGCD(int v1, int v2) {
BigInteger a = new BigInteger(new
StringBuffer().append(v1).toString());
BigInteger b = new BigInteger(new
StringBuffer().append(v2).toString());
BigInteger c = a.gcd(b);
if (c.bitLength() > 31) {
throw new ArithmeticException("Overflow during GCD
computation !!!");
}
return c.intValue();
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.