How can I implement the fraction class java?
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;
}
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
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 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
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.