How can I implement the fraction class java?

578    Asked by MadeleineHill in Java , Asked on Oct 11, 2022

I am writing a bunch of Maths Math related classes: BigInteger, Fraction, matrix, vector, polynomial, set etc. All of these classes will use each other. The classes will either work in decimal format or in Rational format at a time(eg as FractionalMatrix and DecimalMatrix) so I thought it will be best to implement the Fraction class first.

My primary concern is that this is going to be a big project.So, code readability and management is very important.Any suggestions on making the code better are appreciated.

Here is the Fraction class:


public final class Fraction {
private int numerator;
private int denominator;
public Fraction(int numerator,int denominator,boolean wantToReduce) {
    if (denominator == 0) {
        throw new IllegalArgumentException("The denominator is zero.");
    }
    if(numerator==0){
        this.numerator = 0;
        this.denominator = 1;
    }
    else{
    this.numerator = numerator;
    this.denominator = denominator;
    }
    if(denominator<0>        this.numerator = -1*this.numerator;
        this.denominator = -1*this.denominator;
    }
    if(wantToReduce==true)
        this.reduce();
}
public Fraction(int num) {
    this.numerator = num;
    this.denominator = 1;
}
@Override
public String toString() {
    if(denominator!=1)
    return numerator"/"+denominator;
    else
        return numerator"";
}
@Override
public boolean equals(Object obj) {
    if(!(obj instanceof Fraction))
        return false;
    Fraction f = ((Fraction)obj);
    int gcd= Math 2.gcd(numerator,denominator);
    f.reduce();
    if(this.numerator/gcd==f.numerator && this.denominator/gcd == f.denominator)
        return true;
    else
        return false;
}
public Fraction reduce(){
    int gcd = Math 2.gcd(numerator,denominator);
    numerator = numerator/gcd;
    denominator = denominator/gcd;
    return this;
}
//Cannot decide whether to make static methods or not so I randomly picked one. 
public static Fraction add(Fraction f1,Fraction f2,boolean w){
    return new Fraction(f1.numerator*f2.denominator+f2.numerator*f1.denominator,f1.denominator*f2.denominator,w);
}
public static Fraction sub(Fraction f1,Fraction f2,boolean w){
    return new Fraction(f1.numerator*f2.denominator-f2.numerator*f1.denominator,f1.denominator*f2.denominator,w);
}
public static Fraction mul(Fraction f1,Fraction f2,boolean w){
    return new Fraction(f1.numerator*f2.numerator,f1.denominator*f2.denominator,w);
}
public static Fraction div(Fraction f1,Fraction f2,boolean w){
    return new Fraction(f1.numerator*f2.denominator,f1.denominator*f2.numerator,w);
}


}

Here is the Math2.gcd method, I have used The Euclidean Algorithm for finding the GCD.
 public static int gcd(int a,int b){
    if(a<0>        a=-1*a;
    if(b<0>        b=-1*b;
    int t;
    while(b!=0){
        t=b;
        b = a%b;
        a = t;          
    }
    return a;
}


Answered by Mahaboob Alam

General notes about formatting

Your indentation isn't very good. Also, it's usually a good idea to have space between comparator/equal sign and their operand (compute(a) != 0 instead of compute(a)!=0).

You also want to have a space after commas to make the parameters more readable.

Any decent IDE has a code formatter that can solve all these issues :wink:

A few proposals

I'd make another constructor taking two int value and delegating to your first constructor :

public Fraction(final int numerator, final int denominator) {

    this(numerator, denominator, true);

}

Fraction class java should probably be made Serializable. Is it also voluntary that Fraction doesn't implement Comparable ?

It may also be useful to have an immutable constant for Zero instead of always creating a new object for this very common value.

public static final Fraction ZERO = new Fraction(0);

You should add a method that allows you to turn your Fraction into an int (or into your BigInteger class) as well as another one to turn it into a double (or another object of your making) allowing you to cast your fraction to another type.

Step by step analysis

public final class Fraction {

private int numerator;

private int denominator;

Your object is mutable (mainly due to the reduce method). I'm not sure you want it to be immutable (but it's a good idea considering the code) but you should at least make it thread-safe. To turn it into an immutable object, you should make the numerator and denominator final and rework your reduce method as well as your main constructor.

@Override
public String toString() {
    // ...
This one is good, I'd write it as...
@Override
public String toString() {
    return numerator + ((denominator != 1) ? "/" + denominator : "");
}
but that's nit-picking. If you turn your object into an immutable one, it may be worth it to cache the toString result
@Override
public boolean equals(Object obj) {
    // ...
Formatting aside, there are two things that bothers me :
f.reduce();
You are modifying the argument in an equals method !!! ALERT !! If you make the Fraction method immutable this will be solved.
if(this.numerator/gcd==f.numerator && this.denominator/gcd == f.denominator)
    return true;
else
    return false;
This can be simplified to :
return this.numerator/gcd == f.numerator && this.denominator/gcd == f.denominator;
Also, 99.9% of the time you want to have your own hashCode implementation when you modify the equals method so you should consider overriding it. For example :
public int hashCode() {
    final int prime = 919;
    return prime * numerator + denominator;
}

For the add,sub... methods I'd have made them object methods myself but that's really up to you in the end :wink: w is a poor name for the boolean parameter but, aside from that, it's ok.

Your gcd method is good (formatting aside) but you should consider making a short javadoc for that not-so-easy-to-understand method.

[EDIT] : it's better when hashCode gives the same hashCode for two equals objects, as such you should only use a reduced number for your hashCode calculation, the implementation given in my code is thus error-prone :wink:

if you make your object immutable, you'll encounter the following problem

x = new Fraction(4, 2, false);

x.equals(x); // return false

which sadly breaks one of the most basic contracts from equals (reflexivity), you should then only use equals with reduced numbers.



Your Answer

Interviews

Parent Categories