# Fractions in Java

Rashmi Patidar Jun 07, 2021

Mathematically, fractions are the parts or sections of values. When an object is broken equally in definite proportions, the value formed is called a fraction. Fractions are classified into Rational and Irrational Numbers.

In the Java programming language, there is a privilege to perform various operations over fractions like mathematical procedures. One can add, subtract, multiply, and divide over the fractional numbers.

Below is the code block that demonstrates the Rational number operations in the user-defined class.

``````import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RationalNumber {
public final static RationalNumber ZERO = new RationalNumber(BigInteger.ZERO, BigInteger.ONE);

private final BigInteger numerator, denominator;

private RationalNumber(BigInteger numerator, BigInteger denominator) {
this.numerator = numerator;
this.denominator = denominator;
}

private static RationalNumber canonical(BigInteger numerator, BigInteger denominator, boolean checkGcd) {
if (denominator.signum() == 0) {
throw new IllegalArgumentException("denominator is zero");
}
if (numerator.signum() == 0) {
return ZERO;
}
if (denominator.signum() < 0) {
numerator = numerator.negate();
denominator = denominator.negate();
}
if (checkGcd) {
BigInteger gcd = numerator.gcd(denominator);
if (!gcd.equals(BigInteger.ONE)) {
numerator = numerator.divide(gcd);
denominator = denominator.divide(gcd);
}
}
return new RationalNumber(numerator, denominator);
}

public static RationalNumber getInstance(long numerator, long denominator) {
return canonical(new BigInteger("" + numerator), new BigInteger("" + denominator), true);
}

public static RationalNumber valueOf(String s) {
Pattern p = Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
Matcher m = p.matcher(s);
if (!m.matches()) {
throw new IllegalArgumentException("Unknown format '" + s + "'");
}
String whole = m.group(1);
String decimal = m.group(2);
String exponent = m.group(3);
String n = whole;
if (decimal != null) {
n += decimal;
}
BigInteger numerator = new BigInteger(n);
int exp = exponent == null ? 0 : Integer.valueOf(exponent);
int decimalPlaces = decimal == null ? 0 : decimal.length();
exp -= decimalPlaces;
BigInteger denominator;
if (exp < 0) {
denominator = BigInteger.TEN.pow(-exp);
} else {
numerator = numerator.multiply(BigInteger.TEN.pow(exp));
denominator = BigInteger.ONE;
}

return canonical(numerator, denominator, true);
}

public static void main(String[] args) {
RationalNumber r1 = RationalNumber.valueOf("3.14e4");
RationalNumber r2 = RationalNumber.getInstance(111, 7);
convert("r1", r1);
convert("r2", r2);
convert("r1 - r2", r1.subtract(r2));
convert("r1 * r2", r1.multiply(r2));
convert("r1 / r2", r1.divide(r2));
convert("r2 ^ 2", r2.pow(2));
}

public static void convert(String name, RationalNumber r) {
System.out.printf("%s = %s%n", name, r);
System.out.printf("%s.negate() = %s%n", name, r.negate());
System.out.printf("%s.invert() = %s%n", name, r.invert());
System.out.printf("%s.intValue() = %,d%n", name, r.intValue());
System.out.printf("%s.longValue() = %,d%n", name, r.longValue());
System.out.printf("%s.floatValue() = %,f%n", name, r.floatValue());
System.out.printf("%s.doubleValue() = %,f%n", name, r.doubleValue());
System.out.println();
}

if (o.numerator.signum() == 0) {
return this;
} else if (numerator.signum() == 0) {
return o;
} else if (denominator.equals(o.denominator)) {
} else {
}
}

public RationalNumber multiply(RationalNumber o) {
if (numerator.signum() == 0 || o.numerator.signum() == 0) {
return ZERO;
} else if (numerator.equals(o.denominator)) {
return canonical(o.numerator, denominator, true);
} else if (o.numerator.equals(denominator)) {
return canonical(numerator, o.denominator, true);
} else if (numerator.negate().equals(o.denominator)) {
return canonical(o.numerator.negate(), denominator, true);
} else if (o.numerator.negate().equals(denominator)) {
return canonical(numerator.negate(), o.denominator, true);
} else {
return canonical(numerator.multiply(o.numerator), denominator.multiply(o.denominator), true);
}
}

public boolean isInteger() {
return numerator.signum() == 0 || denominator.equals(BigInteger.ONE);
}

public RationalNumber negate() {
return new RationalNumber(numerator.negate(), denominator);
}

public RationalNumber invert() {
return canonical(denominator, numerator, false);
}

public RationalNumber pow(int exp) {
return canonical(numerator.pow(exp), denominator.pow(exp), true);
}

public RationalNumber subtract(RationalNumber o) {
}

public RationalNumber divide(RationalNumber o) {
return multiply(o.invert());
}

public int intValue() {
return isInteger() ? numerator.intValue() : numerator.divide(denominator).intValue();
}

public long longValue() {
return isInteger() ? numerator.longValue() : numerator.divide(denominator).longValue();
}

public float floatValue() {
return (float) doubleValue();
}

public double doubleValue() {
return isInteger() ? numerator.doubleValue() : numerator.doubleValue() / denominator.doubleValue();
}

@Override
public String toString() {
return isInteger() ? String.format("%,d", numerator) : String.format("%,d / %,d", numerator, denominator);
}
}
``````

In the program above, the execution starts from the `main` method. Firstly, a rational number gets initialized using the static `valueOf()` function defined in the class. It takes a string value and performs manipulations over the input String.

It returns a `RationalNumber` of the user-defined type. The function first checks for an input String with proper validations and patterns. The input String gets separated into exponent, decimal, and the whole part. These individual broken values combine to form a rational number.

Another way of creating a rational number is using an `instanceOf()` static factory function. The method internally calls the `canonical` function, which calls a private constructor of the class. The constructor separates and sets the values of the numerator and denominator for a specific instance. By canonical form, it simply means the standard representation form of the rational number.

In the given case, `p/q` is the standard or canonical form where `q!=0` should always be true. The method has the logic written to satisfy the basic conditions of a rational number. It checks for the sign of numerator and denominator separately and performs operations. It checks for denominator values; if it’s zero, the operation throws an exception. It also checks for the greatest common divisor or `gcd` in the numerator and denominator values. The `gcd` function is present in the `BigInteger` class that returns a `BigInteger` value.

Moving ahead, the `convert` method gets called, passing the first rational number instance that gets created. This method also calls upon seven different functions over the rational number instance that gets passed.

Below, you’ll understand each of these methods better:

• Print the rational number in the print stream. Generally, whenever an instance gets printed, the default `toString` method gets called. The method prints the name of the class followed by the hexadecimal representation of the memory location. But here, the function is overridden to give another implementation that represents the number in the `p/q` form.
• The `negate` function will internally negate the rational number by calling the `negate` method of the `BigInteger` class. It will add a minus sign before the rational number.
• The invert function internally calls the `canonical` method with a single difference. It internally passes the third `checkGcd` parameter as false. When the input value is Boolean true, the method logic simplifies the rational number by dividing the fraction by its greatest common divisor. But in this case, the need is to invert without simplification.
• The `intValue` function first checks if the instance is an `Integer` value. `Integers` are numbers that can be positive, negative, or zero but cannot be fractions. So, internally it calls the `divide` method over numerator and denominator. The method is given in the `BigInteger` class and returns a `BigInteger` value. It also throws `ArithmeticException` when the denominator finds a zero value. The returned value gets transformed into an `int` value using `intValue` function.
• The `longValue` function internally calls the divide function snd parse the `BigInteger` output to a `long` datatype.
• The `floatValue` function provides the floating-point value of the rational number. And so as the `doubleValue()` function, which typecasts the output in the `Double` datatype.

The whole process gets called upon an initial rational number instance that is the `r1` instance. A similar sequence is again repeated and gets printed for rational instance `r2`.

## Mathematical Operations for Fractions in Java

Now add, subtract, divide, multiply, and power arithmetic operations need two operands for evaluation. So let’s discuss the methods in detail below:

1. The `add` function first checks for the numerator values if they are positive, negative, or zero. If non-zero, it checks if the denominators of both the rational number are the same. If found the same, it adds the numerator value and returns the rational number formed. Else if not found similar, it defines logic for rational number addition.
2. The `subtract` method internally calls the `add` method after negating the second rational number instance passed.
3. The `multiply` method has quite a complex logic internally. It checks if the numerator is zero of either of the rational number, it returns the output as a zero value. If not zero, it checks the numerator with the denominator of either set. That is the `r1` numerator gets checked with the `r2` denominator and vice-versa. When no condition matches, the numerator of `r1` gets multiplied to `r2` instance numerator, and the denominators of both get multiplied. Finally, it calls the `multiply` function of the `BigInteger` class to perform multiplication.
4. The `divide` function will invert the passed instance and internally call the `multiply` function using the first instance.
5. Last is the `pow` function which evaluates the second power of the `r2` instance. The implementation of `pow` gets defined in the `BigInteger` class that takes the exponent for evaluation. The method throws the `ArithmeticException` exception when the exponent is a negative value.

Below is the output of the complex code given above:

``````r1 = 31,400
r1.negate() = -31,400
r1.invert() = 1 / 31,400
r1.intValue() = 31,400
r1.longValue() = 31,400
r1.floatValue() = 31,400.000000
r1.doubleValue() = 31,400.000000

r2 = 111 / 7
r2.negate() = -111 / 7
r2.invert() = 7 / 111
r2.intValue() = 15
r2.longValue() = 15
r2.floatValue() = 15.857142
r2.doubleValue() = 15.857143

r1 + r2 = 219,911 / 7
r1 + r2.negate() = -219,911 / 7
r1 + r2.invert() = 7 / 219,911
r1 + r2.intValue() = 31,415
r1 + r2.longValue() = 31,415
r1 + r2.floatValue() = 31,415.857422
r1 + r2.doubleValue() = 31,415.857143

r1 - r2 = 219,689 / 7
r1 - r2.negate() = -219,689 / 7
r1 - r2.invert() = 7 / 219,689
r1 - r2.intValue() = 31,384
r1 - r2.longValue() = 31,384
r1 - r2.floatValue() = 31,384.142578
r1 - r2.doubleValue() = 31,384.142857

r1 * r2 = 3,485,400 / 7
r1 * r2.negate() = -3,485,400 / 7
r1 * r2.invert() = 7 / 3,485,400
r1 * r2.intValue() = 497,914
r1 * r2.longValue() = 497,914
r1 * r2.floatValue() = 497,914.281250
r1 * r2.doubleValue() = 497,914.285714

r1 / r2 = 219,800 / 111
r1 / r2.negate() = -219,800 / 111
r1 / r2.invert() = 111 / 219,800
r1 / r2.intValue() = 1,980
r1 / r2.longValue() = 1,980
r1 / r2.floatValue() = 1,980.180176
r1 / r2.doubleValue() = 1,980.180180

r2 ^ 2 = 12,321 / 49
r2 ^ 2.negate() = -12,321 / 49
r2 ^ 2.invert() = 49 / 12,321
r2 ^ 2.intValue() = 251
r2 ^ 2.longValue() = 251
r2 ^ 2.floatValue() = 251.448975
r2 ^ 2.doubleValue() = 251.448980
``````

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.