/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.rational.impl;
import java.math.BigInteger;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.arithmetic.Numbers;
import jmathexpr.arithmetic.integer.impl.LongIntegerNumber;
import jmathexpr.arithmetic.natural.NaturalNumber;
import jmathexpr.arithmetic.natural.impl.LongNaturalNumber;
import jmathexpr.arithmetic.rational.RationalNumber;
import jmathexpr.arithmetic.real.RealNumber;
import jmathexpr.arithmetic.real.impl.DoubleRealNumber;
/**
* Rational number implementation based on two Java long value (separate value
* for the numerator and the denominator).
*
* @author Elemér Furka
*/
public class LongRationalNumber extends RationalNumber {
final long numerator;
final long denominator;
public LongRationalNumber(long numerator, long denominator) {
if (denominator <= 0) {
throw new IllegalArgumentException("Illegal denominator: " + denominator);
}
this.numerator = numerator;
this.denominator = denominator;
}
@Override
public RationalNumber evaluate() {
LongRationalNumber simplified = simplify();
if (simplified.denominator == 1) {
return new LongIntegerNumber(simplified.numerator);
}
else {
return simplified;
}
}
@Override
public LongIntegerNumber numerator() {
return new LongIntegerNumber(numerator);
}
@Override
public LongNaturalNumber denominator() {
return new LongNaturalNumber(denominator);
}
private LongRationalNumber simplify() {
long gcd = gcd(numerator, denominator);
return gcd > 1 ? new LongRationalNumber(numerator / gcd, denominator / gcd) : this;
}
@Override
public ANumber add(ANumber addend) {
if (addend instanceof LongRationalNumber) {
LongRationalNumber other = (LongRationalNumber) addend;
long gcd = gcd(denominator, other.denominator);
long lcm = denominator * other.denominator / gcd;
return new LongRationalNumber(numerator * (lcm / denominator) + other.numerator * (lcm / other.denominator), lcm).evaluate();
} else {
return Numbers.add(this, addend);
}
}
private static long gcd(long long1, long long2) {
return BigInteger.valueOf(long1).gcd(BigInteger.valueOf(long2)).longValue();
}
@Override
public ANumber subtract(ANumber subtrahend) {
if (subtrahend instanceof LongRationalNumber) {
LongRationalNumber other = (LongRationalNumber) subtrahend;
long gcd = gcd(denominator, other.denominator);
long lcm = denominator * other.denominator / gcd;
return new LongRationalNumber(numerator * (lcm / denominator) - other.numerator * (lcm / other.denominator), lcm).evaluate();
} else {
return Numbers.subtract(this, subtrahend);
}
}
@Override
public ANumber multiply(ANumber multiplier) {
if (multiplier instanceof LongRationalNumber) {
LongRationalNumber other = (LongRationalNumber) multiplier;
return new LongRationalNumber(numerator * other.numerator, denominator * other.denominator).evaluate();
} else {
return Numbers.multiply(this, multiplier);
}
}
@Override
public ANumber divide(ANumber divisor) {
if (divisor instanceof LongRationalNumber) {
LongRationalNumber other = (LongRationalNumber) divisor;
if (other.numerator != 0) {
long denom = denominator * other.numerator;
return denom > 0 ?
new LongRationalNumber(numerator * other.denominator, denom).evaluate()
: new LongRationalNumber(-numerator * other.denominator, -denom).evaluate();
} else {
throw new UnsupportedOperationException(
String.format("Division by 0: %s / %s", this, other));
}
} else {
return Numbers.divide(this, divisor);
}
}
@Override
public LongRationalNumber negate() {
return new LongRationalNumber(-numerator, denominator);
}
@Override
public boolean equals(Object object) {
if (object == null) return false;
if (this == object) return true;
if (object instanceof LongRationalNumber) {
LongRationalNumber simplified = simplify();
LongRationalNumber other = ((LongRationalNumber) object).simplify();
return simplified.numerator == other.numerator && simplified.denominator == other.denominator;
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 13 * hash + (int) (this.numerator ^ (this.numerator >>> 32));
hash = 13 * hash + (int) (this.denominator ^ (this.denominator >>> 32));
return hash;
}
@Override
public String toString() {
return String.format("%d/%d", numerator, denominator);
}
@Override
public boolean isNatural() {
LongRationalNumber simplified = simplify();
return simplified.numerator >= 0 && simplified.denominator == 1;
}
@Override
public boolean isInteger() {
LongRationalNumber simplified = simplify();
return simplified.denominator == 1;
}
@Override
public boolean isNegative() {
return numerator < 0;
}
@Override
public boolean isZero() {
return numerator == 0;
}
@Override
public boolean isOne() {
return numerator == denominator;
}
@Override
public ANumber pow(ANumber exponent) {
if (exponent instanceof NaturalNumber) {
LongRationalNumber simplified = simplify();
LongRationalNumber pown =
(LongRationalNumber) new LongIntegerNumber(simplified.numerator).pow(exponent).toRational();
LongRationalNumber powd =
(LongRationalNumber) new LongIntegerNumber(simplified.denominator).pow(exponent).toRational();
return new LongRationalNumber(pown.numerator, powd.numerator);
} else {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
@Override
public RealNumber toReal() {
return new DoubleRealNumber(((double) numerator) / denominator);
}
@Override
public boolean le(ANumber expr) {
if (expr instanceof LongRationalNumber) {
ANumber diff = subtract((LongRationalNumber) expr);
return diff.isNegative() || diff.isZero();
} else {
throw new IllegalArgumentException(expr.getClass() + " Expected: LongRationalNumber");
}
}
@Override
public boolean lt(ANumber expr) {
if (expr instanceof LongRationalNumber) {
ANumber diff = subtract((LongRationalNumber) expr);
return diff.isNegative();
} else {
throw new IllegalArgumentException(expr.getClass() + " Expected: LongRationalNumber");
}
}
}