/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic;
import jmathexpr.AbstractExpression;
import jmathexpr.Constant;
import jmathexpr.Expression;
import jmathexpr.Precedence;
import jmathexpr.SequenceVariable;
import jmathexpr.Variable;
import jmathexpr.arithmetic.integer.IntegerNumber;
import jmathexpr.arithmetic.natural.NaturalNumber;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.rational.RationalNumber;
import jmathexpr.arithmetic.real.RealNumber;
import jmathexpr.arithmetic.real.Reals;
import jmathexpr.set.OrderedPair;
import jmathexpr.set.Set;
import jmathexpr.util.rule.Rule;
/**
* Abstract superclass of all number set classes. All subclasses must implement
* the singleton design pattern.
*
* @author Elemér Furka
*/
public abstract class Numbers extends AbstractExpression implements Set {
protected final char sign;
protected final String unicodeSign;
protected Numbers(char sign, String unicodeSign) {
this.sign = sign;
this.unicodeSign = unicodeSign;
}
@Override
public abstract Set evaluate();
/**
* Tests if the parameters are both numbers and if yes then it returns them
* using the same number representation/implementation.
*
* @param a the first number
* @param b the second number
* @return an OrderedPair instance containing the two (possibly converted)
* numbers
*/
public static OrderedPair toSameType(Expression a, Expression b) {
if (a instanceof NaturalNumber) {
if (b instanceof NaturalNumber) {
return new OrderedPair(a, b);
} else if (b instanceof IntegerNumber) {
return new OrderedPair(((NaturalNumber) a).toInteger(), b);
} else if (b instanceof RationalNumber) {
return new OrderedPair(((NaturalNumber) a).toRational(), b);
} else if (b instanceof RealNumber) {
return new OrderedPair(((NaturalNumber) a).toReal(), b);
}
} else if (a instanceof IntegerNumber) {
if (b instanceof NaturalNumber) {
return new OrderedPair(a, ((NaturalNumber) b).toInteger());
} else if (b instanceof IntegerNumber) {
return new OrderedPair(a, b);
} else if (b instanceof RationalNumber) {
return new OrderedPair(((IntegerNumber) a).toRational(), b);
} else if (b instanceof RealNumber) {
return new OrderedPair(((IntegerNumber) a).toReal(), b);
}
} else if (a instanceof RationalNumber) {
if (b instanceof NaturalNumber) {
return new OrderedPair(a, ((NaturalNumber) b).toRational());
} else if (b instanceof IntegerNumber) {
return new OrderedPair(a, ((IntegerNumber) b).toRational());
} else if (b instanceof RationalNumber) {
return new OrderedPair(a, b);
} else if (b instanceof RealNumber) {
return new OrderedPair(((RationalNumber) a).toReal(), b);
}
} else if (a instanceof RealNumber) {
if (b instanceof NaturalNumber) {
return new OrderedPair(a, ((NaturalNumber) b).toReal());
} else if (b instanceof IntegerNumber) {
return new OrderedPair(a, ((IntegerNumber) b).toReal());
} else if (b instanceof RationalNumber) {
return new OrderedPair(a, ((NaturalNumber) b).toReal());
} else if (b instanceof RealNumber) {
return new OrderedPair(a, b);
}
}
return new OrderedPair(a, b);
}
/**
* Factory method to create a new numerical (real value) constant
* with the given name.
*
* @param name the name of the constant
* @return a new Constant instance
*/
public static Constant constant(String name) {
return new Constant(name, Reals.getInstance());
}
/**
* Factory method to create a new numerical (real value) variable
* with the given name.
*
* @param name the name of the variable
* @return a new Variable instance
*/
public static Variable variable(String name) {
return new Variable(name, Reals.getInstance());
}
/**
* Factory method to create a new (real value) sequence variable
* with the given name.
*
* @param name the name of the variable
* @param index the sequence index
*
* @return a new SequenceVariable instance
*/
public static SequenceVariable variable(String name, long index) {
return new SequenceVariable(name, Naturals.getInstance().create(index), Reals.getInstance());
}
/**
* Tests if the two numbers are equal. Numbers are converted if required.
*
* @param a first number
* @param b second number
*
* @return true if the two numbers are equal
*/
public static boolean equal(ANumber a, ANumber b) {
OrderedPair numbers = toSameType(a, b);
return numbers.a().equals(numbers.b());
}
/**
* Converts the arguments to the same type and performs the addition.
*
* @return the sum of the two numbers
*/
public static ANumber add(ANumber augend, ANumber addend) {
OrderedPair terms = toSameType(augend, addend);
return ((ANumber) terms.a()).add((ANumber) terms.b());
}
/**
* Converts the arguments to the same type and performs a subtraction.
*
* @return the difference of the two numbers
*/
public static ANumber subtract(ANumber minuend, ANumber subtrahend) {
OrderedPair terms = toSameType(minuend, subtrahend);
return ((ANumber) terms.a()).subtract((ANumber) terms.b());
}
/**
* Converts the arguments to the same type and performs a multiplication.
*
* @return the product of the two numbers
*/
public static ANumber multiply(ANumber multiplicand, ANumber multiplier) {
OrderedPair terms = toSameType(multiplicand, multiplier);
return ((ANumber) terms.a()).multiply((ANumber) terms.b());
}
/**
* Converts the arguments to the same type and performs the division.
*
* @return the quotient of the two numbers
*/
public static ANumber divide(ANumber dividend, ANumber divisor) {
OrderedPair terms = toSameType(dividend, divisor);
return ((ANumber) terms.a()).divide((ANumber) terms.b());
}
/**
* Converts the arguments to the same type and tests if the first one is smaller
* than the second one.
*
* @return true if the first argument is smaller than the second one
*/
public static boolean lt(ANumber a, ANumber b) {
OrderedPair terms = toSameType(a, b);
return ((ANumber) terms.a()).lt((ANumber) terms.b());
}
@Override
public boolean isConstant() {
return true;
}
@Override
public boolean isApplicable(Rule rule) {
return rule.matches(this);
}
@Override
public Precedence getPrecedence() {
return Precedence.Evaluation;
}
@Override
public boolean equals(Object object) {
return this == object;
}
@Override
public String toString() {
return Character.toString(sign);
}
@Override
public String toUnicode() {
return unicodeSign;
}
@Override
public String toAsciiMath() {
String s = toString();
return s + s;
}
@Override
public Set union(Set set) {
if (subsetOf(set)) {
return set;
} else if (set.subsetOf(this)) {
return this;
} else {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
}