package org.exist.xquery.value;
import java.text.Collator;
import org.exist.xquery.Constants;
import org.exist.xquery.XPathException;
public abstract class NumericValue extends ComputableValue {
public abstract String getStringValue() throws XPathException;
public abstract AtomicValue convertTo(int requiredType) throws XPathException;
public double getDouble() throws XPathException {
return ((DoubleValue)convertTo(Type.DOUBLE)).getValue();
}
public long getLong() throws XPathException {
return ((IntegerValue)convertTo(Type.INTEGER)).getValue();
}
public int getInt() throws XPathException {
return (int)((IntegerValue)convertTo(Type.INTEGER)).getValue();
}
public abstract boolean hasFractionalPart();
public abstract boolean isNaN();
public abstract boolean isInfinite();
public abstract boolean isZero();
public abstract boolean isNegative();
public abstract boolean isPositive();
public boolean effectiveBooleanValue() throws XPathException {
//If its operand is a singleton value of any numeric type or derived from a numeric type,
//fn:boolean returns false if the operand value is NaN or is numerically equal to zero;
//otherwise it returns true.
return !(isNaN() || isZero());
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#compareTo(int, org.exist.xquery.value.AtomicValue)
*/
public boolean compareTo(Collator collator, int operator, AtomicValue other)
throws XPathException {
if (other.isEmpty()) {
//Never equal, or inequal...
return false;
}
if(Type.subTypeOf(other.getType(), Type.NUMBER)) {
if (isNaN()) {
//NaN does not equal itself.
if (((NumericValue)other).isNaN()) {
return operator == Constants.NEQ;
}
}
double otherVal = ((NumericValue)other).getDouble();
double val = getDouble();
switch(operator) {
case Constants.EQ:
return val == otherVal;
case Constants.NEQ:
return val != otherVal;
case Constants.GT:
return val > otherVal;
case Constants.GTEQ:
return val >= otherVal;
case Constants.LT:
return val < otherVal;
case Constants.LTEQ:
return val <= otherVal;
default:
throw new XPathException("Type error: cannot apply operator to numeric value");
}
}
throw new XPathException("Type error: cannot compare operands: " +
Type.getTypeName(getType()) + " and " +
Type.getTypeName(other.getType()));
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#compareTo(org.exist.xquery.value.AtomicValue)
*/
public int compareTo(Collator collator, AtomicValue other) throws XPathException {
if(Type.subTypeOf(other.getType(), Type.NUMBER)) {
if (isNaN()) {
//NaN does not equal itself.
if (((NumericValue)other).isNaN())
return Constants.INFERIOR;
}
double otherVal = ((NumericValue)other).getDouble();
double val = getDouble();
if(val == otherVal)
return Constants.EQUAL;
else if(val > otherVal)
return Constants.SUPERIOR;
else
return Constants.INFERIOR;
} else {
throw new XPathException("cannot compare numeric value to non-numeric value");
}
}
public abstract NumericValue negate() throws XPathException;
public abstract NumericValue ceiling() throws XPathException;
public abstract NumericValue floor() throws XPathException;
public abstract NumericValue round() throws XPathException;
public abstract NumericValue round(IntegerValue precision) throws XPathException;
public abstract NumericValue mod(NumericValue other) throws XPathException;
//TODO : implement here ?
public abstract IntegerValue idiv(NumericValue other) throws XPathException;
public abstract NumericValue abs() throws XPathException;
public abstract AtomicValue max(Collator collator, AtomicValue other) throws XPathException;
public abstract AtomicValue min(Collator collator, AtomicValue other) throws XPathException;
}