package edu.vtc.cis3030
/**
* This class represents rational numbers (fractions). This version is inspired by the example
* in Chapter 6 of PiS. It illustrates how to set up a simple but useful immutable class.
*
* @param n The numerator.
* @param d The denominator.
*/
class Rational1(n: Int, d: Int = 1) {
// Precondition on the constructor. Throw an exception for zero denominators.
require(d != 0, "invalid Rational denominator")
// Compiler might optimizes these fields away.
// They are private and not needed after construction.
private val commonDivisor = gcd(n.abs, d.abs)
private val signFlag = integerSign(n) * integerSign(d)
// Constructor initializes these (public) vals.
val numerator: Int = signFlag * (n.abs / commonDivisor)
val denominator: Int = d.abs / commonDivisor
// Override the toString method so rational numbers can be displayed in a nice way.
override def toString: String = numerator + "/" + denominator
// The usual arithmetic operations...
def +(that: Rational1): Rational1 = {
val newNumerator = (numerator * that.denominator) + (that.numerator * denominator)
val newDenominator = denominator * that.denominator
new Rational1(newNumerator, newDenominator)
}
def -(that: Rational1): Rational1 = {
val newNumerator = (numerator * that.denominator) - (that.numerator * denominator)
val newDenominator = denominator * that.denominator
new Rational1(newNumerator, newDenominator)
}
def *(that: Rational1): Rational1 =
new Rational1(numerator * that.numerator, denominator * that.denominator)
def /(that: Rational1): Rational1 =
new Rational1(numerator * that.denominator, denominator * that.numerator)
// Private helper method to extract the sign of an integer value.
private def integerSign(n: Int): Int =
if (n < 0) -1 else 1
// Private helper method to compute the greatest common divisor with Euclid's Algorithm.
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
}
/**
* Companion object to the Rational1 class above.
*/
object Rational1 {
/**
* Factory method to create rational numbers. This allows one to use the class name as if it
* was the name of a function to build a rational object without using 'new.' The default
* value of 'd' allows one to create a rational object from an integer as in: Rational1(5) to
* construct 5/1.
*
* @param n The numerator.
* @param d The denominator.
*/
def apply(n: Int, d: Int = 1) = new Rational1(n, d)
}