Cancelling fractions

The following exercise requires the import of the previous Maven based exercise Finding the greatest common divisor of two integer values . The import may be effected by:

  1. Creating a local Maven jar archive export by executing mvn install in project Finding the greatest common divisor of two integer values at the command line. Alternatively you may right click on your pom.xml file in Eclipse hitting Run as Maven build using install as goal.

  2. Defining Finding the greatest common divisor of two integer values as a dependency ❶ in your current project:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation=
     "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>de.hdm-stuttgart.de.sd1</groupId>
      <artifactId>fraction</artifactId>
      <version>1.0</version>
      <packaging>jar</packaging>
    
      <name>fraction</name>
        ...
      <dependencies>
        <dependency> <groupId>de.hdm-stuttgart.de.sd1</groupId>
          <artifactId>gcd</artifactId>
          <version>1.0</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
            ...
        </dependency>
      </dependencies>
    </project>
Figure 288. Defining a dependency to another Maven artifact. Slide presentation Create comment in forum
Defining a dependency to another Maven artifact.

exercise No. 107

Cancelling fractions Create comment in forum

Q:

We have implemented GCD computation in Finding the greatest common divisor of two integer values . The current exercises idea is to implement cancelling of fractions by using the method long getGcd(long a, long b). Change the following implementation items:

  • The constructor should cancel a fraction if required, see introductory remark.

  • The Methods mult(...) and add(...) should cancel any resulting Fraction instance. It might be worth to consider a defensive strategy to avoid unnecessary overflow errors.

Test your results.

A:

Modifying the constructor is straightforward: On creating a fraction we simply divide both numerator and denominator by the GCD value:

public Fraction(long numerator, long denominator) {
  final long gcd = Math.getGcd(numerator, denominator);

  setNumerator(numerator / gcd);
  setDenominator(denominator / gcd);
}

Its tempting to implement mult(...) in a simple fashion:

public Fraction mult2(Fraction f) {
  return new Fraction(numerator * f.numerator,
        denominator * f.denominator);
}

This is however too shortsighted. Consider the example 4 7 3 2 . Our simple implementation proposal would call new Fraction(12, 14) only to discover a GCD value of 4. Having larger argument values this might cause an unnecessary overflow. Moreover the GCD calculation will take longer than needed.

We may instead transform the term in question by exchanging the numerators like 3 7 4 2 to enable cancelling prior to multiplying. Now the call new Fraction(4,2) will construct the representation 2 1 and finishing the computation will yield the correct result 6 7 . We should thus implement:

public Fraction mult(Fraction f) {
  final Fraction f1 = new Fraction(f.numerator, denominator),
                 f2 = new Fraction(numerator, f.denominator);

  return new Fraction(f1.numerator * f2.numerator,
      f1.denominator * f2.denominator);
}

Similar reflections lead to the clue decomposing the denominators when implementing add(...). This is what you'd do as well if your task was adding two fractions by hand trying to avoid large numbers:

public Fraction add(Fraction f) {

  final long gcd = Math.getGcd(denominator, f.denominator);

  return new Fraction( numerator * (f.denominator / gcd) +
      (denominator / gcd) * f.numerator, (denominator / gcd) * f.denominator);
}

See complete implementation here. We may re-use out test:

public static void main(String[] args) {

  // Input
  final Fraction
    twoThird = new Fraction(2, 3),          // Construct a fraction object (2/3)
    threeSeven = new Fraction(3, 7);        // Construct a fraction object (3/7)

  // Computed results
  final Fraction
    sum = twoThird.add(threeSeven),         // (2/3) + (3/7)
    product = twoThird.mult(threeSeven);    // (2/3) * (3/7)

  System.out.println("(2/3) + (3/7) = (23/21) = " + sum.getValue());
  System.out.println("(2/3) * (3/7) = (2/7) = " + product.getValue());
}