Rat.java
package edu.udel.cis.vsl.sarl.simplify.eval;
import java.math.BigInteger;
import edu.udel.cis.vsl.sarl.IF.SARLException;
import edu.udel.cis.vsl.sarl.IF.number.RationalNumber;
/**
* A mutable infinite precision rational number.
*
* @author siegel
*/
class Rat {
BigInteger a; // numerator
BigInteger b; // denominator
/**
* Construct new rational number from numerator a and denominator b. Place
* it into canonical form: b>0; a/b=0 iff (a=0 and b=1); gcd(a,b)=1.
*
* @param a
* the numerator
* @param b
* the denominator
*/
Rat(BigInteger a, BigInteger b) {
this.a = a;
this.b = b;
normalize();
}
/**
* Constructs new rational number a=a/1.
*
* @param a
* the big integer value
*/
Rat(BigInteger a) {
this.a = a;
this.b = BigInteger.ONE;
}
/**
* Constructs new rational number copying the numerator and denominator from
* the given rational number.
*
* @param that
* the other rational number
*/
Rat(Rat that) {
a = that.a;
b = that.b;
}
/**
* Constructs new rational number from a SARL {@link RationalNumber}, which
* uses the same canonical form. (The reason why we aren't using SARL
* {@link RationalNumber}s is because they are all flyweighted (cached),
* which is too expensive for the huge numbers we need in this class.)
*
* @param that
* the SARL number to copy
*/
Rat(RationalNumber that) {
a = that.numerator();
b = that.denominator();
}
/**
* Places this rational number into canonic form.
*/
private void normalize() {
int signum = b.signum();
if (signum == 0) {
throw new ArithmeticException("Division by 0");
}
// ensures any negation is in numerator
if (signum < 0) {
a = a.negate();
b = b.negate();
}
// canonical form for 0 is 0/1 :
if (a.signum() == 0) {
b = BigInteger.ONE;
} else if (!b.equals(BigInteger.ONE)) {
BigInteger gcd = a.gcd(b);
if (!gcd.equals(BigInteger.ONE)) {
a = a.divide(gcd);
b = b.divide(gcd);
}
}
}
/**
* Add that number to this one. Modifies this number so that its new value
* is the sum of its old value and that. Does not modify that.
*
* @param that
* the other value
*/
void add(Rat that) {
a = a.multiply(that.b).add(b.multiply(that.a));
b = b.multiply(that.b);
normalize();
}
/**
* Modifies this number so that its new value is the product of its old
* value and that. Does not modify that.
*
* @param that
* the other value
*/
void multiply(Rat that) {
a = a.multiply(that.a);
b = b.multiply(that.b);
normalize();
}
/**
* Modifies this number by raising it to the {@code exponent} power.
*
* @param exponent
* a positive int
*/
void power(int exponent) {
a = a.pow(exponent);
b = b.pow(exponent);
// no need to normalize: (a,b)=1 --> (a^e,b^e)=1
}
/**
* Modifies this number by raising it to the {@code exp} power.
*
* @param exp
* a positive big integer
*/
void power(BigInteger exp) {
try {
power(exp.intValueExact());
return;
} catch (ArithmeticException e) {
throw new SARLException("to be implemented");
// need basic implementation using multiplication
}
}
/**
* Is this rational number equal to 0?
*
* @return {@code true} iff this is 0
*/
boolean isZero() {
return a.signum() == 0;
}
@Override
public boolean equals(Object object) {
if (object instanceof Rat) {
Rat that = (Rat) object;
return a.equals(that.a) && b.equals(that.b);
}
return false;
}
@Override
public int hashCode() {
return a.hashCode() ^ b.hashCode();
}
}