working code :D
/*
Name: Samar Qureshi
Date: 12/11/21
Description: The Fractions class part of the Numbers project is able to work with and manipulate a Fraction object, which is retrieved from the
client code, FractionMain. Capabilities include, but are not limited to: basic math operations (addition, subtraction, multiplication,
division, reciprocating, simplifying), as well as other advanced functions such as elegant format (done by Jennifer), converting from a
mixed number to an improper fraction and vice versa, evaluating exponents of a fraction, converting from a decimal to fraction and vice
versa, and sorting a group of fractions from greatest to least (found in the client code).
*/
public class Fraction {
//instance variables
private long denominator, numerator, wholeNumber, mixedNumerator;
private int numeratorExponent, denominatorExponent;
private boolean mixedNeg, wholeNeg, denomNeg;
public Fraction(){ //constructor
numerator = 0;
denominator = 1;
wholeNumber = 0;
mixedNumerator = 0;
numeratorExponent = 1;
denominatorExponent = 1;
mixedNeg = false;
wholeNeg = false;
}
public Fraction(long newNumerator, long newDenominator){ //overloaded constructor for regular fractions
numerator = newNumerator;
denominator = newDenominator;
}
public Fraction(long newWholeNumber, long newMixedNumerator, long newDenominator){ //overloaded constructor for mixed numbers
mixedNumerator = newMixedNumerator;
denominator = newDenominator;
wholeNumber = newWholeNumber;
}
// Takes in a long value, then sets it as the numerator
public void setNumerator(long newNumerator){
numerator = newNumerator;
}
//Returns the numerator as a long value
public long getNumerator(){
return numerator;
}
//Takes in a long value, then sets it as the denominator
public void setDenominator(long newDenominator){
denominator = newDenominator;
}
//Returns the denominator as a long value
public long getDenominator(){
return denominator;
}
//Takes in a long value, then sets it as the whole number in a mixed fraction
public void setWholeNumber(long newWholeNumber){
wholeNumber = newWholeNumber;
}
//Returns the whole number of a mixed fraction as a long value
public long getWholeNumber(){
return wholeNumber;
}
//Takes in a long value, then sets it as the numerator in a mixed fraction
public void setMixedNumerator(int newMixedNumerator){
mixedNumerator = newMixedNumerator;
}
//Returns the numerator of a mixed fraction as a long value
public long getMixedNumerator(){
return mixedNumerator;
}
public void setNumeartorExponent(int newNumeratorExponent){
numeratorExponent = newNumeratorExponent;
}
////Returns the exponent of the numerator as an integer
public int getNumeratorExponent(){
return numeratorExponent;
}
//Takes in a an integer value, then sets it as the exponent of the denominator
public void setDenominatorExponent(int newDenominatorExponent){
denominatorExponent = newDenominatorExponent;
}
//Returns the exponent of the denominator as an integer
public int getDenominatorExponent(){
return denominatorExponent;
}
/*
Adds two fraction objects together, creates a common denominator by "cross multiplying", and then calls on the
simplify() method to reduce the fraction to its lowest terms
Pre: two fraction objects that are inputted by the user
Post: resulting fraction object is the sum of the two user inputted fraction objects, does not return a fraction,
rather, changes the value of the numerator and denominator of the original fraction object so that those instance
variables can now be passed to formatFraction()
*/
public void add(Fraction frac2){
numerator = (frac2.getDenominator()*numerator) + (denominator*frac2.getNumerator());
denominator *=frac2.getDenominator();
simplify();
//frac1 becomes the sum
}
/*
Subtracts two fraction objects, creates a common denominator by "cross multiplying", and then calls on the
simplify() method to reduce the fraction to its lowest terms
Pre: two fraction objects that are inputted by the user
Post: resulting fraction object is the difference of the two user inputted fraction objects, does not return a fraction,
rather, changes the value of the numerator and denominator of the original fraction object so that those instance
variables can now be passed to formatFraction()
*/
public void subtract(Fraction frac2){
numerator = (frac2.getDenominator()*numerator) - (denominator*frac2.getNumerator());
denominator *=frac2.getDenominator();
simplify();
//frac1 becomes the difference
}
/*
Multiplies two fractions together by finding the product of the two numerators, and the product of the two denominators,
then calls on the simplify() method that reduces the fraction object to its simpliest form
Pre: two fraction objects that are inputted by the user
Post: resulting fraction object is the product of the two user inputted fraction objects, does not return a fraction,
rather, changes the value of the numerator and denominator of the original fraction object so that those instance
variables can now be passed to formatFraction()
*/
public void multiply(Fraction frac2){
numerator *= frac2.getNumerator();
denominator *= frac2.getDenominator();
simplify();
}
/*
Divides two user inputted Fraction objects by eachother the same way as the multiply() method, except the first fraction
object is now being multiplied by the reciprocal of the second fraction object
Pre: two fraction objects that are inputted by the user
Post: resulting fraction object is the quotient of the two user inputted fraction objects, does not return a fraction,
rather, changes the value of the numerator and denominator of the original fraction object so that those instance
variables can now be passed to formatFraction()
*/
public void divide(Fraction frac2){
numerator *= frac2.getDenominator();
denominator*=frac2.getNumerator();
simplify();
}
/*
Simplifies a fraction by determining the greatest common factor between in the numerator and denominator, then divides
the the numerator and denominator by the the GCF, which results in the reduced form of the fraction object
Pre: fraction object
Post: the reduced or simplified form of the same Fraction object
*/
public void simplify(){
//evaluateExponents();
long gcf = gcf(denominator, numerator); //initally reducing the Fraction
numerator /= gcf;
denominator /= gcf;
mixedNumerator/=gcf;
if(numerator < 0 && denominator < 0){
// if the numerator and denominator are negative, it reduces to a fully postive Fraction
numerator = Math.abs(numerator);
// mixedNumerator = Math.abs(mixedNumerator);
denominator = Math.abs(denominator);
}
if(mixedNumerator < 0 && denominator < 0){
// if the numerator in a mixed fraction and denominator are negative, it reduces to a fully postive Fraction
mixedNumerator = Math.abs(mixedNumerator);
denominator = Math.abs(denominator);
}
if(mixedNumerator < 0 && wholeNumber < 0){
// if the wholeNumber of a mixed fraction and denominator are negative, it reduces to a fully postive Fraction
mixedNumerator = Math.abs(mixedNumerator);
}
if(numerator%denominator==0){
//if the fraction can be reduced to a whole number
wholeNumber = numerator/denominator;
// numerator = 0;
// denominator = 1;
}
}
/*
Determines the greatest common factor of two numbers (usually the numerator and the denominator), which is then utilized in the
simplify() method to reduce the Fraction object
Pre: takes in two numbers as long data types
Post: returns a single long, which is the greatest common factor or divisor between the two numbers
*/
public long gcf(long num1, long num2){
while(Math.abs(num2)>0){
//keeps traversing through until it has found the greatest number that is able to divide evenly into num1 and num2
long temp = num2;
num2 = num1%num2;
num1 = temp;
}
return num1;
}
/*
Overrides the .equals() method for Objects, is rewritten in such a way that it can be utilized to determine if two fraction objects are
equal to eachother, regardless if they have the exact same initial numerator and denominator
Pre: Takes in the current Fraction object, along with a second Fraction object as a parameter
Post: returns a boolean value based off of the comparison between the two Fraction objects
*/
public boolean equals(Fraction frac){
//checks to see if two fractions are equal to eachother
simplify(); //simplifies the original fraaction object
frac.simplify(); //simplifies the parameter fraction object
if(numerator==frac.getNumerator() && denominator==frac.getDenominator()){
return true;
}
return false;
}
/*
Converts a mixed number into an improper fraction
Pre: takes in the whole number, the numerator (mixedNumerator), and the denominator, all inputted by the user in FractionMain
Post: modifies the numerator and denominator of the Fraction in which it is the correct improper fraction; then is simplified
before being passed to formatImproper
*/
public void mixedToImproper(){
if(numerator < 0 || mixedNumerator < 0 || wholeNumber < 0){ //checks if the numerator is negative
mixedNeg = true;
}
// if(wholeNumber < 0){
// wholeNeg = true;
// }
if(denominator < 0){
denomNeg = true;
}
numerator = Math.abs(mixedNumerator) + Math.abs(wholeNumber*denominator);
wholeNumber = 0;
simplify();
}
/*
Converts an improper fraction into a mixed number
Pre: takes in the numerator and denominator using accessor methods
Post: simpifies the improper fraction, then modifies the mixedNumerator, the wholeNumber and the denominator to the equivalent
mixed number fraction before being passed to formatMixed
*/
public void improperToMixed(){
simplify(); // cancel out negatives if needed
wholeNumber = numerator/denominator; // long (data type) division truncates
// the given fraction was negative but since the whole number is 0, we must make sure a negative will be displayed.
if (numerator < 0 || denominator < 0) {
wholeNeg = true;
}
// the numerator & denominator should be positive since the whole number will be negative if necessary
mixedNumerator = (long) Math.abs(numerator % denominator);
denominator = (long) Math.abs(denominator);
}
/*
Evalutates exponents of the numerator and denominator
Pre: utilizes accessor methods to get the numerator and denomaintor, as well as their respective exponents
Post: the resulting numerator and denominator instance variables after evalutaing the their exponents
*/
public void evaluateExponents(){
if(numeratorExponent > denominatorExponent && numerator == denominator){ //if the bases are the same
numeratorExponent -= denominatorExponent;
}
else if(denominatorExponent > numeratorExponent && numerator == denominator ){
denominatorExponent -= numeratorExponent;
}
//manually evaluating the exponents, regardless of the bases in relation to their respective exponent
numerator = (long)Math.pow(numerator, numeratorExponent);
denominator = (long)Math.pow(denominator, denominatorExponent);
}
/*
Finds the reciprocal of a Fraction object
Pre: utilizes accessor methods to get the numerator and the denominator
Post: modifies the numerator and denominator so that their values match the expected reciprocal
*/
public void reciprocate(){
if(wholeNumber > 0){
mixedToImproper();
numerator = denominator;
denominator = mixedNumerator;
}
else{
numerator = denominator;
denominator = numerator;
}
}
/*
One line simple output for any Fraction object, as opposed to formatFraction
Pre: takes the Fraction object
Post: returns the Fraction object in its respective String format
*/
public String toString(){
//slow build the fraction
if(wholeNumber!=0){
return wholeNumber + " " + (mixedNumerator + "/" + denominator);
}
return(numerator + "/" + denominator);
}
/*
JENNIFER'S METHOD: Outputs the numerator and denominator in an elegant three line manner
Pre: numerator and denominator instance variables as longs
Post: a 2D String array that graphically depicts the expected output
*/
public String[] formatFraction(long numerator, long denominator) {
// declarations & initializations
String[] returnArr = new String[3];
int lengthN = (numerator + "").length();
int lengthD = (denominator + "").length();
int length;
// find length of fraction bar
if (lengthN > lengthD) {
length = lengthN + 2;
} else {
length = lengthD + 2;
}
returnArr = setEmptyStrings(returnArr);
// find out which value has more digits (numerator vs. denominator) & format the numerator & denominators accordingly
if (lengthN > lengthD && (lengthN - lengthD) % 2 == 1) {
returnArr[0] = getSpaces((length - lengthN) / 2) + numerator + getSpaces((length - lengthN) / 2);
returnArr[2] = getSpaces((length - lengthD) / 2) + denominator + getSpaces((length - lengthD) / 2 + 1); // +1 space right of the denominator to ensure that everything after it will continue to be centered
} else if ((lengthD - lengthN) % 2 == 1) {
returnArr[0] = getSpaces((length - lengthN) / 2) + numerator + getSpaces((length - lengthN) / 2 + 1);
returnArr[2] = getSpaces((length - lengthD) / 2) + denominator + getSpaces((length - lengthD) / 2);
} else {
returnArr[0] = getSpaces((length - lengthN) / 2) + numerator + getSpaces((length - lengthN) / 2);
returnArr[2] = getSpaces((length - lengthD) / 2) + denominator + getSpaces((length - lengthD) / 2);
}
// format fraction bar based on length (add hyphens)
for (int i = 0; i < length; i++) {
returnArr[1] += "-";
}
return returnArr;
}
/*
JENNIFER'S METHOD: returns String containing the specified number of spaces
Pre: integer numSpaces; specifies number of spaces
Post: returns empty string
*/
public String getSpaces(int numSpaces) {
// declare & initialize an empty string to be returned at the end
String returnStr = "";
// add spaces to the return string
for (int i = 0; i < numSpaces; i++) {
returnStr += " ";
}
return returnStr;
}
/*
JENNIFER'S METHOD: fills up String array with empty spaces
Pre: null String array
Post: String array with "" in every index
*/
public static String[] setEmptyStrings(String[] arr) {
// traverse through every element in the String array, and sets each index to an empty String
for (int i = 0; i < arr.length; i++) {
arr[i] = "";
}
return arr;
}
/*
Formats a mixed fraction by calling on formatFraction()
Pre: takes in the instance variables of mixedNumerator, denominator and the whole number
Post: graphically formats them in a 2D String array from formatFraction()
*/
public String[] formatMixed(){
// NO NEED SINCE THE WHOLE NUMBER WAS ALREADY CALCULATED; IF IT'S NEGATIVE, THEN IT'LL ALEADY BE NEGATIVE
//formats correctly if there is a negative needed that was found in improperToMixed()
if(wholeNeg && wholeNumber == 0){
return formatFraction(-mixedNumerator, denominator); // numerator will be negative
}
return formatFraction(mixedNumerator, denominator);
}
/*
Formats an improper fraction by calling on formatFraction()
Pre: takes in the instance variables of numerator and denominator
Post: graphically formats them in a 2D String array from formatFraction()
*/
public String[] formatImproper(){
if(wholeNeg || mixedNeg){
//formats correctly if there was a negative found in mixedToImproper
numerator = -numerator;
mixedNumerator = -mixedNumerator;
}
if(denomNeg){
denominator = -denominator;
}
return formatFraction(numerator, denominator);
}
/*
Takes in a decimal, then converts it into fraction
Pre: Takes in the String decimal, which is the user input, with an expected '.' to represent the decimal
Post: modifies the Fraction object so that the numerator and denominator are reflective of the the respective decimal
*/
public void decimalToFrac(String decimal){
boolean negDecimal = false;
if(decimal.charAt(0) == '-'){ //checks if the decimal is negative
negDecimal = true;
decimal = decimal.substring(1,decimal.length());
//modifies the length of the String so that it is only looking at the absolute value
}
for(int i = 0; i<decimal.length(); i++){
if(decimal.charAt(i)== '.'){
int numberOfDecimals = decimal.length()-decimal.indexOf(".")-1; //calculates number of decimal places after the decimal
decimal = decimal.substring(0, decimal.indexOf(".")) + decimal.substring(decimal.indexOf(".")+1, decimal.length());
denominator = (long)Math.pow(10,numberOfDecimals); //denominator has as many zeros as there are decimal places
}
}
numerator = parseLong(decimal); //parses the String to long data type
if(negDecimal){ //accounts for if decimal inputted was initially negative
numerator = -numerator;
}
simplify();
//System.out.println(numerator + "/" + denominator);
}
/*
Calculates a decimal by doing real division on the numerator and the denominator
Pre: Takes in the instance variables denominator and numerator
Post: returns the double, which is the corresponding decimal
*/
public double calcDecimal(){
// if(wholeNumber > 0){
// mixedToImproper(); //if the fraction is mixed it will convert it into improper before it goes converted to decimal
// }
// if(wholeNeg || mixedNeg){
// return -(Math.abs(wholeNumber) + Math.abs((double)numerator/(double)denominator));
// }
return (double)numerator/(double)denominator;
// return Math.abs(wholeNumber) + Math.abs((double)numerator/(double)denominator);
}
/*
Parses a String into a long data type so the resulting value can be used in a Fraction object
Pre: Takes in a user inputted String
Post: returns a long data type, which is is the "long casted" respective String
*/
public static long parseLong(String s) {
//takes in a String and converts it into a long
long num = 0;
int location = 1;
for (int i = s.length()-1; i >= 0; i--) {
num += (s.charAt(i) - '0') * location;
location *= 10;
}
return num;
}
}