/* * @(#)JPTParser.java 2.5.0 18 May 2007 * * Copyright 2007 * College of Computer and Information Science * Northeastern University * Boston, MA 02115 * * The Java Power Tools software may be used for educational * purposes as long as this copyright notice is retained intact * at the top of all source files. * * To discuss possible commercial use of this software, * contact Richard Rasala at Northeastern University, * College of Computer and Information Science, * 617-373-2462 or rasala@ccs.neu.edu. * * The Java Power Tools software has been designed and built * in collaboration with Viera Proulx and Jeff Raab. * * Should this software be modified, the words "Modified from * Original" must be included as a comment below this notice. * * All publication rights are retained. This software or its * documentation may not be published in any media either * in whole or in part without explicit permission. * * This software was created with support from Northeastern * University and from NSF grant DUE-9950829. */ package edu.neu.ccs.parser; import edu.neu.ccs.*; import edu.neu.ccs.util.*; import java.text.*; import java.util.*; import java.math.*; // debug // import edu.neu.ccs.console.*; /** *
Parses and evaulates data Strings
* using simple expression evaluation.
* *
The grammar used in this parsing is similar to * that defined within the Java Language Specification * by James Gosling, Bill Joy, and Guy Steele but as * of 2.5.0 we have made significant additions to aid * the user of these facilities in interactive mode.
* *As of 2.5.0, the parser algorithms have all been
* refactored down to the new base class called
* BaseParser. The purpose of this class
* is therefore to define and install constants,
* operations, and functions. Each such entity is now
* public static final so they may be utilized by some
* other class that extends BaseParser if
* so desired.
The constants, functions, and operations are all
* commented individually. Summary tables of the
* constants, functions, and operations are provided
* immediately below and repeated in the comments for
* the methods
* addConstants(),
* addFunctions(), and
* addOperations().
* The summary tables for operations show precedence.
This class now provides an exponentiation operator
* denoted ^ that attempts exponentiation
* as an integral computation if possible. This is in
* contrast to the power function that
* always uses Math.pow in its
* implementation. By choosing ^ or
* power, the user may select implementation.
The function definitions continue to throw exceptions * if given incorrect arguments but will no longer throw * exceptions if mathematical errors occur. Rather the * computation proceeds as in Java itself to produce either * an infinity or NaN.
* *Constant definitions:
* *| Identifier | *Type | *Definition | *
| true | *XBoolean | *true | *
| false | *XBoolean | *false | *
| pi | *XDouble | *Math.PI | *
| e | *XDouble | *Math.E | *
| MaxInt | *XInt | *Integer.MAX_VALUE | *
| maxint | *XInt | *Integer.MAX_VALUE | *
| MinInt | *XInt | *Integer.MIN_VALUE | *
| minint | *XInt | *Integer.MIN_VALUE | *
| MaxLong | *XLong | *Long.MAX_VALUE | *
| maxlong | *XLong | *Long.MAX_VALUE | *
| MinLong | *XLong | *Long.MIN_VALUE | *
| minlong | *XLong | *Long.MIN_VALUE | *
| MaxDouble | *XDouble | *Double.MAX_VALUE | *
| maxdouble | *XDouble | *Double.MAX_VALUE | *
| MinDouble | *XDouble | *Double.MIN_VALUE | *
| mindouble | *XDouble | *Double.MIN_VALUE | *
| Infinity | *XDouble | *Double.POSITIVE_INFINITY | *
| infinity | *XDouble | *Double.POSITIVE_INFINITY | *
| NaN | *XDouble | *Double.NaN | *
| nan | *XDouble | *Double.NaN | *
Function definitions:
* *| Function Name | *Typical Usage | *
| abs | *abs(x) | *
| ceiling | *ceiling(x) | *
| floor | *floor(x) | *
| round | *round(x) | *
| max | *max(x,y) | *
| min | *min(x,y) | *
| sqrt | *sqrt(x) | *
| power | *power(x,y) | *
| root | *root(x,y) | *
| todegrees | *todegrees(theta) | *
| toradians | *toradians(angle) | *
| sin | *sin(theta) | *
| sindeg | *sindeg(angle) | *
| cos | *cos(theta) | *
| cosdeg | *cosdeg(angle) | *
| tan | *tan(theta) | *
| tandeg | *tandeg(angle) | *
| asin | *asin(s) | *
| asindeg | *asindeg(s) | *
| acos | *acos(c) | *
| acosdeg | *acosdeg(c) | *
| atan | *atan(t) | *
| atandeg(t) | *atandeg(t) | *
| atan2 | *atan2(y,x) | *
| atan2deg | *atan2deg(y,x) | *
| exp | *exp(x) | *
| log | *log(x) | *
| ln | *ln(x) | *
| log2 | *log2(x) | *
| log10 | *log10(x) | *
| logtobase | *logtobase(x,b) | *
In the above table:
* x and y
* stand for generic variables;
* theta
* is an angle in radians;
* angle
* is an angle in degrees;
*
* s, c, t
* stand for possible values of
* sin, cos, tan;
* and b
* is the base for a logarithm.
In 2.5.0, random was removed from the
* list of functions because as implemented in the class
* AbstractFunction a function has a fixed
* number of arguments. Instead, random is
* now implemented directly in BaseParser
* to take one of three forms with the following
* interpretations.
| Function Name | *Typical Usage | *Interpretation | *
| random | *random() | *Random number between 0 and 1 | *
| random | *random(x) | *Random number between 0 and x | *
| random | *random(x,y) | *Random number between x and y | *
Operation definitions:
* *| Precedence | *Operations | *Symbols | *
| 0 | *IDENTITY | *None | *
| 1 | *operationOR | *|| | *
| 2 | *operationAND | *&& | *
| 3 | *operationEQ operationNE | *== != | *
| 4 | *operationLT operationGT operationLE operationGE | *< > <= >= | *
| 5 | *operationPlus operationMinus | *+ - | *
| 6 | *operationTimes operationSlash operationPercent | ** / % | *
| 7 | *operationCaret | *^ | *
| 8 | *operationNOT | *! | *
abs. */
public static final AbstractFunction functionAbs =
new AbstractFunction("abs", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0])) {
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
BigInteger va = a.getValue();
int test = va.compareTo(BigInteger.ZERO);
if (test >= 0)
return a;
va = va.negate();
return new XBigInteger(va);
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
if (vx >= 0)
return x;
return new XDouble(-vx);
}
};
/** AbstractFunction to implement ceiling. */
public static final AbstractFunction functionCeiling =
new AbstractFunction("ceiling", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0])) {
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
return a;
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
vx = Math.ceil(vx);
return new XDouble(vx);
}
};
/** AbstractFunction to implement floor. */
public static final AbstractFunction functionFloor =
new AbstractFunction("floor", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0])) {
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
return a;
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
vx = Math.floor(vx);
return new XDouble(vx);
}
};
/** AbstractFunction to implement round. */
public static final AbstractFunction functionRound =
new AbstractFunction("round", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0])) {
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
return a;
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
vx = Math.rint(vx);
return new XDouble(vx);
}
};
/** AbstractFunction to implement max. */
public static final AbstractFunction functionMax =
new AbstractFunction("max", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0]) &&
ParserUtilities.isXIntegral(values[1]))
{
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
XBigInteger b =
ParserUtilities.toXBigInteger((XNumber) values[1]);
BigInteger va = a.getValue();
BigInteger vb = b.getValue();
int test = va.compareTo(vb);
if (test >= 0)
return a;
return b;
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
double vx = x.getValue();
double vy = y.getValue();
if (vx >= vy)
return x;
return y;
}
};
/** AbstractFunction to implement min. */
public static final AbstractFunction functionMin =
new AbstractFunction("min", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
if (ParserUtilities.isXIntegral(values[0]) &&
ParserUtilities.isXIntegral(values[1]))
{
XBigInteger a =
ParserUtilities.toXBigInteger((XNumber) values[0]);
XBigInteger b =
ParserUtilities.toXBigInteger((XNumber) values[1]);
BigInteger va = a.getValue();
BigInteger vb = b.getValue();
int test = va.compareTo(vb);
if (test >= 0)
return b;
return a;
}
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
double vx = x.getValue();
double vy = y.getValue();
if (vx >= vy)
return y;
return x;
}
};
/**
* AbstractFunction to implement sqrt
* based on Math.sqrt.
*/
public static final AbstractFunction functionSqrt =
new AbstractFunction("sqrt", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.sqrt(vx));
}
};
/**
* AbstractFunction to implement power
* based on Math.pow.
*
* @see #operationCaret
*/
public static final AbstractFunction functionPower =
new AbstractFunction("power", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
double vx = x.getValue();
double vy = y.getValue();
return new XDouble(Math.pow(vx, vy));
}
};
/**
* AbstractFunction to implement root
* based on MathUtilities.root.
*/
public static final AbstractFunction functionRoot =
new AbstractFunction("root", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
double vx = x.getValue();
double vy = y.getValue();
return new XDouble(MathUtilities.root(vx, vy));
}
};
/**
* AbstractFunction to implement todegrees
* based on Math.toDegrees.
*/
public static final AbstractFunction functionToDegrees =
new AbstractFunction("todegrees", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.toDegrees(vx));
}
};
/**
* AbstractFunction to implement toradians
* based on Math.toRadians.
*/
public static final AbstractFunction functionToRadians =
new AbstractFunction("toradians", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.toRadians(vx));
}
};
/**
* AbstractFunction to implement sin
* based on Math.sin.
*/
public static final AbstractFunction functionSin =
new AbstractFunction("sin", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.sin(vx));
}
};
/**
* AbstractFunction to implement sindeg
* based on Math.sin
* and appropriate degrees to radians conversion.
*/
public static final AbstractFunction functionSinDeg =
new AbstractFunction("sindeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.sin(Math.toRadians(vx)));
}
};
/**
* AbstractFunction to implement cos
* based on Math.cos.
*/
public static final AbstractFunction functionCos =
new AbstractFunction("cos", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.cos(vx));
}
};
/**
* AbstractFunction to implement cosdeg
* based on Math.cos
* and appropriate degrees to radians conversion.
*/
public static final AbstractFunction functionCosDeg =
new AbstractFunction("cosdeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.cos(Math.toRadians(vx)));
}
};
/**
* AbstractFunction to implement tan
* based on Math.tan.
*/
public static final AbstractFunction functionTan =
new AbstractFunction("tan", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.tan(vx));
}
};
/**
* AbstractFunction to implement tandeg
* based on Math.tan
* and appropriate degrees to radians conversion.
*/
public static final AbstractFunction functionTanDeg =
new AbstractFunction("tandeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.tan(Math.toRadians(vx)));
}
};
/**
* AbstractFunction to implement asin
* based on Math.asin.
*/
public static final AbstractFunction functionASin =
new AbstractFunction("asin", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.asin(vx));
}
};
/**
* AbstractFunction to implement asindeg
* based on Math.asin
* and appropriate radians to degrees conversion.
*/
public static final AbstractFunction functionASinDeg =
new AbstractFunction("asindeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.toDegrees(Math.asin(vx)));
}
};
/**
* AbstractFunction to implement acos
* based on Math.acos.
*/
public static final AbstractFunction functionACos =
new AbstractFunction("acos", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.acos(vx));
}
};
/**
* AbstractFunction to implement acosdeg
* based on Math.acos
* and appropriate radians to degrees conversion.
*/
public static final AbstractFunction functionACosDeg =
new AbstractFunction("acosdeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.toDegrees(Math.acos(vx)));
}
};
/**
* AbstractFunction to implement atan
* based on Math.atan.
*/
public static final AbstractFunction functionATan =
new AbstractFunction("atan", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.atan(vx));
}
};
/**
* AbstractFunction to implement atandeg
* based on Math.atan
* and appropriate radians to degrees conversion.
*/
public static final AbstractFunction functionATanDeg =
new AbstractFunction("atandeg", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.toDegrees(Math.atan(vx)));
}
};
/**
* AbstractFunction to implement atan2
* based on Math.atan2.
*/
public static final AbstractFunction functionATan2 =
new AbstractFunction("atan2", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
// note that for atan2, y precedes x
XDouble y = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble x = ParserUtilities.toXDouble((XNumber) values[1]);
double vy = y.getValue();
double vx = x.getValue();
return new XDouble(Math.atan2(vy, vx));
}
};
/**
* AbstractFunction to implement atan2deg
* based on Math.atan2
* and appropriate radians to degrees conversion.
*/
public static final AbstractFunction functionATan2Deg =
new AbstractFunction("atan2deg", 2)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
// note that for atan2deg, y precedes x
XDouble y = ParserUtilities.toXDouble((XNumber) values[0]);
XDouble x = ParserUtilities.toXDouble((XNumber) values[1]);
double vy = y.getValue();
double vx = x.getValue();
return new XDouble(Math.toDegrees(Math.atan2(vy, vx)));
}
};
/**
* AbstractFunction to implement exp
* based on Math.exp.
*/
public static final AbstractFunction functionExp =
new AbstractFunction("exp", 1)
{
public Object functionCall(Object[] values)
throws ParseException
{
checkValuesAsNumeric(values);
XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
double vx = x.getValue();
return new XDouble(Math.exp(vx));
}
};
/**
* AbstractFunction to implement log
* based on Math.log.
This is identical to ln.
AbstractFunction to implement ln
* based on Math.log.
This is identical to log.
AbstractFunction to implement log2.
* *
log2(x) is computed as:
Math.log(x) / Math.log(2)
AbstractFunction to implement log10.
* *
log10(x) is computed as:
Math.log(x) / Math.log(10)
AbstractFunction to implement logtobase.
* *
logtobase(x,b) is computed as:
Math.log(x) / Math.log(b)
NumericOperation to implement plus.
* *Symbol: "+".
* *Unary and binary.
*/ public static final NumericOperation operationPlus = new NumericOperation("+", true, true) { public Object unaryForXIntegral(XBigInteger a) { return a; } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); return new XBigInteger(va.add(vb)); } public Object unaryForXFloating(XDouble x) { return x; } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(vx + vy); } }; /** *NumericOperation to implement minus.
* *Symbol: "-".
* *Unary and binary.
*/ public static final NumericOperation operationMinus = new NumericOperation("-", true, true) { public Object unaryForXIntegral(XBigInteger a) { BigInteger va = a.getValue(); return new XBigInteger(va.negate()); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); return new XBigInteger(va.subtract(vb)); } public Object unaryForXFloating(XDouble x) { double vx = x.getValue(); return new XDouble(-vx); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(vx - vy); } }; /** *NumericOperation to implement times.
* *Symbol: "*".
* *Binary.
*/ public static final NumericOperation operationTimes = new NumericOperation("*", false, true) { public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); return new XBigInteger(va.multiply(vb)); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(vx * vy); } }; /** *NumericOperation to implement division.
* *Symbol: "/".
* *Binary.
*/ public static final NumericOperation operationSlash = new NumericOperation("/", false, true) { public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); if (vb.equals(BigInteger.ZERO)) { int test = va.compareTo(BigInteger.ZERO); if (test > 0) return new XDouble(Double.POSITIVE_INFINITY); if (test < 0) return new XDouble(Double.NEGATIVE_INFINITY); return new XDouble(Double.NaN); } return new XBigInteger(va.divide(vb)); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(vx / vy); } }; /** *NumericOperation to implement remainder.
* *Symbol: "%".
* *Binary.
*/ public static final NumericOperation operationPercent = new NumericOperation("%", false, true) { public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); if (vb.equals(BigInteger.ZERO)) return new XDouble(Double.NaN); return new XBigInteger(va.remainder(vb)); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(vx % vy); } }; /** *NumericOperation to implement exponentiation.
* *Symbol: "^".
* *Binary.
* *If the arguments are integral, that is, of type
* XBigInteger, then an effort will be
* made to carry out the exponentiation in integral
* arithmetic.
If the arguments are not integral or if it is
* impossible to do an integral computation, then
* this method reverts to using Math.pow.
This operation is more subtle than the function
* functionPower introduced in this class.
* The power function always uses Math.pow
* and makes no attempt to handle integral arguments in
* a special way.
It is intentional that this operation and the power * function operate differently. In some cases, the user * may want an integral computation but in other cases if * the internal BigInteger would be extremely large may * actually perfer to do the computation using double * precision floating point.
* * @see #functionPower */ public static final NumericOperation operationCaret = new NumericOperation("^", false, true) { private final BigInteger ZERO = BigInteger.ZERO; private final BigInteger ONE = BigInteger.ONE; private final BigInteger MINUSONE = ONE.negate(); public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); // special cases if (vb.equals(ZERO)) return new XBigInteger(ONE); int test = vb.compareTo(ZERO); if (va.equals(ZERO)) { if (test > 0) return new XBigInteger(ZERO); else return new XDouble(Double.NaN); } if (va.equals(ONE)) return new XBigInteger(ONE); if (va.equals(MINUSONE)) { int lowbit = vb.getLowestSetBit(); if (lowbit == 0) return new XBigInteger(MINUSONE); else return new XBigInteger(ONE); } // if vb is equivalent to a positive int exponent // then use the BigInteger pow function if (test > 0) { // get the associated exponent as an int int exponent = vb.intValue(); // prepare to test if vb equals exponent String bits = Integer.toBinaryString(exponent); BigInteger vc = new BigInteger(bits, 2); // if vb equals exponent use BigInteger pow if (vb.equals(vc)) { return new XBigInteger(va.pow(exponent)); } } // otherwise compute in double precision double vx = va.doubleValue(); double vy = vb.doubleValue(); return new XDouble(Math.pow(vx, vy)); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XDouble(Math.pow(vx, vy)); } }; /** *BooleanOperation to implement equals.
* *Symbol: "==".
* *Binary. All types.
*/ public static final BooleanOperation operationEQ = new BooleanOperation("==", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp == vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test == 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx == vy); } }; /** *BooleanOperation to implement not equals.
* *Symbol: "!=".
* *Binary. All types.
*/ public static final BooleanOperation operationNE = new BooleanOperation("!=", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp != vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test != 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx != vy); } }; /** *BooleanOperation to implement less than.
* *Symbol: "<".
* *Binary. All types.
*/ public static final BooleanOperation operationLT = new BooleanOperation("<", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(!vp && vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test < 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx < vy); } }; /** *BooleanOperation to implement greater than.
* *Symbol: ">".
* *Binary. All types.
*/ public static final BooleanOperation operationGT = new BooleanOperation(">", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp && !vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test > 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx > vy); } }; /** *BooleanOperation to implement less than or equals.
* *Symbol: "<=".
* *Binary. All types.
*/ public static final BooleanOperation operationLE = new BooleanOperation("<=", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(!vp || vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test <= 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx <= vy); } }; /** *BooleanOperation to implement greater than or equals.
* *Symbol: ">=".
* *Binary. All types.
*/ public static final BooleanOperation operationGE = new BooleanOperation(">=", false, true, true) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp || !vq); } public Object binaryForXIntegral(XBigInteger a, XBigInteger b) { BigInteger va = a.getValue(); BigInteger vb = b.getValue(); int test = va.compareTo(vb); return new XBoolean(test >= 0); } public Object binaryForXFloating(XDouble x, XDouble y) { double vx = x.getValue(); double vy = y.getValue(); return new XBoolean(vx >= vy); } }; /** *BooleanOperation to implement "and".
* *Symbol: "&&".
* *Binary. Boolean only.
*/ public static final BooleanOperation operationAND = new BooleanOperation("&&", false, true, false) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp && vq); } }; /** *BooleanOperation to implement "or".
* *Symbol: "||".
* *Binary. Boolean only.
*/ public static final BooleanOperation operationOR = new BooleanOperation("||", false, true, false) { public Object binaryForXBoolean(XBoolean p, XBoolean q) { boolean vp = p.getValue(); boolean vq = q.getValue(); return new XBoolean(vp || vq); } }; /** *BooleanOperation to implement "not".
* *Symbol: "!".
* *Binary. Boolean only.
*/ public static final BooleanOperation operationNOT = new BooleanOperation("!", true, false, false) { public Object unaryForXBoolean(XBoolean p) { boolean vp = p.getValue(); return new XBoolean(! vp); } }; ///////////// // Methods // ///////////// /** *Adds the standard constants for this parser * to the environment.
* *| Identifier | *Type | *Definition | *
| true | *XBoolean | *true | *
| false | *XBoolean | *false | *
| pi | *XDouble | *Math.PI | *
| e | *XDouble | *Math.E | *
| MaxInt | *XInt | *Integer.MAX_VALUE | *
| maxint | *XInt | *Integer.MAX_VALUE | *
| MinInt | *XInt | *Integer.MIN_VALUE | *
| minint | *XInt | *Integer.MIN_VALUE | *
| MaxLong | *XLong | *Long.MAX_VALUE | *
| maxlong | *XLong | *Long.MAX_VALUE | *
| MinLong | *XLong | *Long.MIN_VALUE | *
| minlong | *XLong | *Long.MIN_VALUE | *
| MaxDouble | *XDouble | *Double.MAX_VALUE | *
| maxdouble | *XDouble | *Double.MAX_VALUE | *
| MinDouble | *XDouble | *Double.MIN_VALUE | *
| mindouble | *XDouble | *Double.MIN_VALUE | *
| Infinity | *XDouble | *Double.POSITIVE_INFINITY | *
| infinity | *XDouble | *Double.POSITIVE_INFINITY | *
| NaN | *XDouble | *Double.NaN | *
| nan | *XDouble | *Double.NaN | *
Adds the standard functions for this parser * to the function table.
* *| Function Name | *Typical Usage | *
| abs | *abs(x) | *
| ceiling | *ceiling(x) | *
| floor | *floor(x) | *
| round | *round(x) | *
| max | *max(x,y) | *
| min | *min(x,y) | *
| sqrt | *sqrt(x) | *
| power | *power(x,y) | *
| root | *root(x,y) | *
| todegrees | *todegrees(theta) | *
| toradians | *toradians(angle) | *
| sin | *sin(theta) | *
| sindeg | *sindeg(angle) | *
| cos | *cos(theta) | *
| cosdeg | *cosdeg(angle) | *
| tan | *tan(theta) | *
| tandeg | *tandeg(angle) | *
| asin | *asin(s) | *
| asindeg | *asindeg(s) | *
| acos | *acos(c) | *
| acosdeg | *acosdeg(c) | *
| atan | *atan(t) | *
| atandeg(t) | *atandeg(t) | *
| atan2 | *atan2(y,x) | *
| atan2deg | *atan2deg(y,x) | *
| exp | *exp(x) | *
| log | *log(x) | *
| ln | *ln(x) | *
| log2 | *log2(x) | *
| log10 | *log10(x) | *
| logtobase | *logtobase(x,b) | *
In the above table:
* x and y
* stand for generic variables;
* theta
* is an angle in radians;
* angle
* is an angle in degrees;
*
* s, c, t
* stand for possible values of
* sin, cos, tan;
* and b
* is the base for a logarithm.
In 2.5.0, random was removed from the
* list of functions because as implemented in the class
* AbstractFunction a function has a fixed
* number of arguments. Instead, random is
* now implemented directly in BaseParser
* to take one of three forms with the following
* interpretations.
| Function Name | *Typical Usage | *Interpretation | *
| random | *random() | *Random number between 0 and 1 | *
| random | *random(x) | *Random number between 0 and x | *
| random | *random(x,y) | *Random number between x and y | *
Adds the standard operations for this parser * to the operation table.
* *Except for the introduction of the ^
* operation, follows Arnold, Gosling, Holmes:
The Java Programming Language, Third Edition, 6.10
* *| Precedence | *Operations | *Symbols | *
| 0 | *IDENTITY | *None | *
| 1 | *operationOR | *|| | *
| 2 | *operationAND | *&& | *
| 3 | *operationEQ operationNE | *== != | *
| 4 | *operationLT operationGT operationLE operationGE | *< > <= >= | *
| 5 | *operationPlus operationMinus | *+ - | *
| 6 | *operationTimes operationSlash operationPercent | ** / % | *
| 7 | *operationCaret | *^ | *
| 8 | *operationNOT | *! | *