/* * @(#)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:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
IdentifierTypeDefinition
trueXBooleantrue
falseXBooleanfalse
piXDoubleMath.PI
eXDoubleMath.E
MaxIntXIntInteger.MAX_VALUE
maxintXIntInteger.MAX_VALUE
MinIntXIntInteger.MIN_VALUE
minintXIntInteger.MIN_VALUE
MaxLongXLongLong.MAX_VALUE
maxlongXLongLong.MAX_VALUE
MinLongXLongLong.MIN_VALUE
minlongXLongLong.MIN_VALUE
MaxDoubleXDoubleDouble.MAX_VALUE
maxdoubleXDoubleDouble.MAX_VALUE
MinDoubleXDoubleDouble.MIN_VALUE
mindoubleXDoubleDouble.MIN_VALUE
InfinityXDoubleDouble.POSITIVE_INFINITY
infinityXDoubleDouble.POSITIVE_INFINITY
NaNXDoubleDouble.NaN
nanXDoubleDouble.NaN
* *

Function definitions:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Function NameTypical Usage
absabs(x)
ceilingceiling(x)
floorfloor(x)
roundround(x)
maxmax(x,y)
minmin(x,y)
sqrtsqrt(x)
powerpower(x,y)
rootroot(x,y)
todegreestodegrees(theta)
toradianstoradians(angle)
sinsin(theta)
sindegsindeg(angle)
coscos(theta)
cosdegcosdeg(angle)
tantan(theta)
tandegtandeg(angle)
asinasin(s)
asindegasindeg(s)
acosacos(c)
acosdegacosdeg(c)
atanatan(t)
atandeg(t)atandeg(t)
atan2atan2(y,x)
atan2degatan2deg(y,x)
expexp(x)
loglog(x)
lnln(x)
log2log2(x)
log10log10(x)
logtobaselogtobase(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 NameTypical UsageInterpretation
randomrandom()Random number between 0 and 1
randomrandom(x)Random number between 0 and x
randomrandom(x,y)Random number between x and y
* *

Operation definitions:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
PrecedenceOperationsSymbols
0IDENTITYNone
1operationOR||
2operationAND&&
3operationEQ operationNE== !=
4operationLT operationGT operationLE operationGE< > <= >=
5operationPlus operationMinus+ -
6operationTimes operationSlash operationPercent* / %
7operationCaret^
8operationNOT!
* * @author Richard Rasala * @author Jeff Raab * @version 2.5.0 * @since 1.0 * @see * Java Language Specification */ public class JPTParser extends BaseParser // debug // implements ConsoleAware { ////////////////////////////////// // AbstractFunction Definitions // ////////////////////////////////// /** AbstractFunction to implement 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.

*/ public static final AbstractFunction functionLog = new AbstractFunction("log", 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.log(vx)); } }; /** *

AbstractFunction to implement ln * based on Math.log.

* *

This is identical to log.

*/ public static final AbstractFunction functionLn = new AbstractFunction("ln", 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.log(vx)); } }; /** *

AbstractFunction to implement log2.

* *

log2(x) is computed as:

* *

Math.log(x) / Math.log(2)

*/ public static final AbstractFunction functionLog2 = new AbstractFunction("log2", 1) { private final double log2 = Math.log(2); public Object functionCall(Object[] values) throws ParseException { checkValuesAsNumeric(values); XDouble x = ParserUtilities.toXDouble((XNumber) values[0]); double vx = x.getValue(); return new XDouble(Math.log(vx) / log2); } }; /** *

AbstractFunction to implement log10.

* *

log10(x) is computed as:

* *

Math.log(x) / Math.log(10)

*/ public static final AbstractFunction functionLog10 = new AbstractFunction("log10", 1) { private final double log10 = Math.log(10); public Object functionCall(Object[] values) throws ParseException { checkValuesAsNumeric(values); XDouble x = ParserUtilities.toXDouble((XNumber) values[0]); double vx = x.getValue(); return new XDouble(Math.log(vx) / log10); } }; /** *

AbstractFunction to implement logtobase.

* *

logtobase(x,b) is computed as:

* *

Math.log(x) / Math.log(b)

*/ public static final AbstractFunction functionLogToBase = new AbstractFunction("logtobase", 2) { public Object functionCall(Object[] values) throws ParseException { checkValuesAsNumeric(values); XDouble x = ParserUtilities.toXDouble((XNumber) values[0]); XDouble b = ParserUtilities.toXDouble((XNumber) values[1]); double vx = x.getValue(); double vb = b.getValue(); return new XDouble(Math.log(vx) / Math.log(vb)); } }; /////////////////////////// // Operation Definitions // /////////////////////////// /** *

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.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
IdentifierTypeDefinition
trueXBooleantrue
falseXBooleanfalse
piXDoubleMath.PI
eXDoubleMath.E
MaxIntXIntInteger.MAX_VALUE
maxintXIntInteger.MAX_VALUE
MinIntXIntInteger.MIN_VALUE
minintXIntInteger.MIN_VALUE
MaxLongXLongLong.MAX_VALUE
maxlongXLongLong.MAX_VALUE
MinLongXLongLong.MIN_VALUE
minlongXLongLong.MIN_VALUE
MaxDoubleXDoubleDouble.MAX_VALUE
maxdoubleXDoubleDouble.MAX_VALUE
MinDoubleXDoubleDouble.MIN_VALUE
mindoubleXDoubleDouble.MIN_VALUE
InfinityXDoubleDouble.POSITIVE_INFINITY
infinityXDoubleDouble.POSITIVE_INFINITY
NaNXDoubleDouble.NaN
nanXDoubleDouble.NaN
*/ protected void addConstants() { addConstant("true", new XBoolean(true)); addConstant("false", new XBoolean(false)); addConstant("pi", new XDouble(Math.PI)); addConstant("e", new XDouble(Math.E)); addConstant("MaxInt", new XInt(Integer.MAX_VALUE)); addConstant("maxint", new XInt(Integer.MAX_VALUE)); addConstant("MinInt", new XInt(Integer.MIN_VALUE)); addConstant("minint", new XInt(Integer.MIN_VALUE)); addConstant("MaxLong", new XLong(Long.MAX_VALUE)); addConstant("maxlong", new XLong(Long.MAX_VALUE)); addConstant("MinLong", new XLong(Long.MIN_VALUE)); addConstant("minlong", new XLong(Long.MIN_VALUE)); addConstant("MaxDouble", new XDouble(Double.MAX_VALUE)); addConstant("maxdouble", new XDouble(Double.MAX_VALUE)); addConstant("MinDouble", new XDouble(Double.MIN_VALUE)); addConstant("mindouble", new XDouble(Double.MIN_VALUE)); addConstant("Infinity", new XDouble(Double.POSITIVE_INFINITY)); addConstant("infinity", new XDouble(Double.POSITIVE_INFINITY)); addConstant("NaN", new XDouble(Double.NaN)); addConstant("nan", new XDouble(Double.NaN)); } /** *

Adds the standard functions for this parser * to the function table.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Function NameTypical Usage
absabs(x)
ceilingceiling(x)
floorfloor(x)
roundround(x)
maxmax(x,y)
minmin(x,y)
sqrtsqrt(x)
powerpower(x,y)
rootroot(x,y)
todegreestodegrees(theta)
toradianstoradians(angle)
sinsin(theta)
sindegsindeg(angle)
coscos(theta)
cosdegcosdeg(angle)
tantan(theta)
tandegtandeg(angle)
asinasin(s)
asindegasindeg(s)
acosacos(c)
acosdegacosdeg(c)
atanatan(t)
atandeg(t)atandeg(t)
atan2atan2(y,x)
atan2degatan2deg(y,x)
expexp(x)
loglog(x)
lnln(x)
log2log2(x)
log10log10(x)
logtobaselogtobase(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 NameTypical UsageInterpretation
randomrandom()Random number between 0 and 1
randomrandom(x)Random number between 0 and x
randomrandom(x,y)Random number between x and y
*/ protected void addFunctions() { addFunction(functionAbs); addFunction(functionCeiling); addFunction(functionFloor); addFunction(functionRound); addFunction(functionMax); addFunction(functionMin); addFunction(functionSqrt); addFunction(functionPower); addFunction(functionRoot); addFunction(functionToDegrees); addFunction(functionToRadians); addFunction(functionSin); addFunction(functionSinDeg); addFunction(functionCos); addFunction(functionCosDeg); addFunction(functionTan); addFunction(functionTanDeg); addFunction(functionASin); addFunction(functionASinDeg); addFunction(functionACos); addFunction(functionACosDeg); addFunction(functionATan); addFunction(functionATanDeg); addFunction(functionATan2); addFunction(functionATan2Deg); addFunction(functionExp); addFunction(functionLog); addFunction(functionLn); addFunction(functionLog2); addFunction(functionLog10); addFunction(functionLogToBase); } /** *

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

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
PrecedenceOperationsSymbols
0IDENTITYNone
1operationOR||
2operationAND&&
3operationEQ operationNE== !=
4operationLT operationGT operationLE operationGE< > <= >=
5operationPlus operationMinus+ -
6operationTimes operationSlash operationPercent* / %
7operationCaret^
8operationNOT!
* * @see #operationCaret */ protected void addOperations() { addOperationAfterPrecedenceOf(IDENTITY , operationOR ); addOperationAfterPrecedenceOf(operationOR , operationAND ); addOperationAfterPrecedenceOf(operationAND , operationEQ ); addOperationAtPrecedenceOf (operationEQ , operationNE ); addOperationAfterPrecedenceOf(operationEQ , operationLT ); addOperationAtPrecedenceOf (operationLT , operationGT ); addOperationAtPrecedenceOf (operationLT , operationLE ); addOperationAtPrecedenceOf (operationLT , operationGE ); addOperationAfterPrecedenceOf(operationLT , operationPlus ); addOperationAtPrecedenceOf (operationPlus , operationMinus ); addOperationAfterPrecedenceOf(operationPlus , operationTimes ); addOperationAtPrecedenceOf (operationTimes , operationSlash ); addOperationAtPrecedenceOf (operationTimes , operationPercent ); addOperationAfterPrecedenceOf(operationTimes , operationCaret ); addOperationAfterPrecedenceOf(operationCaret , operationNOT ); } }