jscl.math.Rational Maven / Gradle / Ivy
package jscl.math;
import jscl.math.function.Constant;
import jscl.math.function.Fraction;
import jscl.math.function.Inverse;
import jscl.mathml.MathML;
import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;
public final class Rational extends Generic implements Field {
public static final Rational factory = new Rational(BigInteger.valueOf(0), BigInteger.valueOf(1));
final BigInteger numerator;
final BigInteger denominator;
public Rational(BigInteger numerator, BigInteger denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public BigInteger numerator() {
return numerator;
}
public BigInteger denominator() {
return denominator;
}
public Rational add(Rational rational) {
BigInteger gcd = denominator.gcd(rational.denominator);
BigInteger c = denominator.divide(gcd);
BigInteger c2 = rational.denominator.divide(gcd);
return new Rational(numerator.multiply(c2).add(rational.numerator.multiply(c)), denominator.multiply(c2)).reduce();
}
Rational reduce() {
BigInteger gcd = numerator.gcd(denominator);
if (gcd.signum() != denominator.signum()) gcd = gcd.negate();
return gcd.signum() == 0 ? this : new Rational(numerator.divide(gcd), denominator.divide(gcd));
}
@Nonnull
public Generic add(@Nonnull Generic that) {
if (that instanceof Rational) {
return add((Rational) that);
} else if (that instanceof JsclInteger) {
return add(valueOf(that));
} else {
return that.valueOf(this).add(that);
}
}
public Rational multiply(Rational rational) {
BigInteger gcd = numerator.gcd(rational.denominator);
BigInteger gcd2 = denominator.gcd(rational.numerator);
return new Rational(numerator.divide(gcd).multiply(rational.numerator.divide(gcd2)), denominator.divide(gcd2).multiply(rational.denominator.divide(gcd)));
}
@Nonnull
public Generic multiply(@Nonnull Generic that) {
if (that instanceof Rational) {
return multiply((Rational) that);
} else if (that instanceof JsclInteger) {
return multiply(valueOf(that));
} else {
return that.multiply(this);
}
}
@Nonnull
public Generic divide(@Nonnull Generic that) throws NotDivisibleException {
if (that instanceof Rational) {
return multiply(that.inverse());
} else if (that instanceof JsclInteger) {
return divide(valueOf(that));
} else {
return that.valueOf(this).divide(that);
}
}
public Generic inverse() {
if (signum() < 0) return new Rational(denominator.negate(), numerator.negate());
else return new Rational(denominator, numerator);
}
public Rational gcd(Rational rational) {
return new Rational(numerator.gcd(rational.numerator), scm(denominator, rational.denominator));
}
public Generic gcd(@Nonnull Generic generic) {
if (generic instanceof Rational) {
return gcd((Rational) generic);
} else if (generic instanceof JsclInteger) {
return gcd(valueOf(generic));
} else {
return generic.valueOf(this).gcd(generic);
}
}
static BigInteger scm(BigInteger b1, BigInteger b2) {
return b1.multiply(b2).divide(b1.gcd(b2));
}
@Nonnull
public Generic gcd() {
return null;
}
public Generic pow(int exponent) {
return null;
}
public Generic negate() {
return new Rational(numerator.negate(), denominator);
}
public int signum() {
return numerator.signum();
}
public int degree() {
return 0;
}
public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
return multiply(variable.expressionValue());
}
public Generic derivative(@Nonnull Variable variable) {
return JsclInteger.valueOf(0);
}
public Generic substitute(@Nonnull Variable variable, Generic generic) {
return this;
}
public Generic expand() {
return this;
}
public Generic factorize() {
return expressionValue().factorize();
}
public Generic elementary() {
return this;
}
public Generic simplify() {
return reduce();
}
public Generic numeric() {
return new NumericWrapper(this);
}
public Generic valueOf(Generic generic) {
if (generic instanceof Rational) {
Rational r = (Rational) generic;
return new Rational(r.numerator, r.denominator);
} else if (generic instanceof Expression) {
boolean sign = generic.signum() < 0;
Generic g[] = ((Fraction) (sign ? generic.negate() : generic).variableValue()).getParameters();
JsclInteger numerator = (JsclInteger) (sign ? g[0].negate() : g[0]);
JsclInteger denominator = (JsclInteger) g[1];
return new Rational(numerator.content(), denominator.content());
} else {
JsclInteger en = (JsclInteger) generic;
return new Rational(en.content(), BigInteger.valueOf(1));
}
}
public Generic[] sumValue() {
try {
if (integerValue().signum() == 0) return new Generic[0];
else return new Generic[]{this};
} catch (NotIntegerException e) {
return new Generic[]{this};
}
}
public Generic[] productValue() throws NotProductException {
try {
if (integerValue().compareTo(JsclInteger.valueOf(1)) == 0) return new Generic[0];
else return new Generic[]{this};
} catch (NotIntegerException e) {
return new Generic[]{this};
}
}
public Power powerValue() throws NotPowerException {
return new Power(this, 1);
}
public Expression expressionValue() throws NotExpressionException {
return Expression.valueOf(this);
}
public JsclInteger integerValue() throws NotIntegerException {
if (denominator.compareTo(BigInteger.ONE) == 0) {
return new JsclInteger(numerator);
} else {
throw new NotIntegerException();
}
}
@Override
public boolean isInteger() {
try {
integerValue();
return true;
} catch (NotIntegerException e) {
return false;
}
}
public Variable variableValue() throws NotVariableException {
try {
integerValue();
throw new NotVariableException();
} catch (NotIntegerException e) {
if (numerator.compareTo(BigInteger.valueOf(1)) == 0) return new Inverse(new JsclInteger(denominator));
else return new Fraction(new JsclInteger(numerator), new JsclInteger(denominator));
}
}
public Variable[] variables() {
return new Variable[0];
}
public boolean isPolynomial(@Nonnull Variable variable) {
return true;
}
public boolean isConstant(@Nonnull Variable variable) {
return true;
}
public int compareTo(Rational rational) {
int c = denominator.compareTo(rational.denominator);
if (c < 0) return -1;
else if (c > 0) return 1;
else return numerator.compareTo(rational.numerator);
}
public int compareTo(Generic generic) {
if (generic instanceof Rational) {
return compareTo((Rational) generic);
} else if (generic instanceof JsclInteger) {
return compareTo(valueOf(generic));
} else {
return generic.valueOf(this).compareTo(generic);
}
}
public String toString() {
final StringBuilder result = new StringBuilder();
try {
result.append(integerValue());
} catch (NotIntegerException e) {
result.append(numerator);
result.append("/");
result.append(denominator);
}
return result.toString();
}
public String toJava() {
return "JsclDouble.valueOf(" + numerator + "/" + denominator + ")";
}
public void toMathML(MathML element, Object data) {
int exponent = data instanceof Integer ? (Integer) data : 1;
if (exponent == 1) bodyToMathML(element);
else {
MathML e1 = element.element("msup");
bodyToMathML(e1);
MathML e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(exponent)));
e1.appendChild(e2);
element.appendChild(e1);
}
}
@Nonnull
@Override
public Set extends Constant> getConstants() {
return Collections.emptySet();
}
void bodyToMathML(MathML element) {
try {
MathML e1 = element.element("mn");
e1.appendChild(element.text(String.valueOf(integerValue())));
element.appendChild(e1);
} catch (NotIntegerException e) {
MathML e1 = element.element("mfrac");
MathML e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(numerator)));
e1.appendChild(e2);
e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(denominator)));
e1.appendChild(e2);
element.appendChild(e1);
}
}
}