import javax.swing.JOptionPane; // allows GUI import java.util.*; // ExprEvaluator class //33 // Revised 11/24/05, 4/8/06, 3/8/08, 3/10/08, 3/15/08, 3/20/08, 5/12/08, // 5/19/08, 6/7/08, 6/10/08, 6/18/08, 6/23/08, 6/15/13 // 7/29/18 (Corrected subtype of random to 20) // added functions roundTo, toRadians, toDegrees. /** * Beta 6.0 *
* The ExprEvaluator class is designed to be used in applications and applets * when it is desired to allow the user to type in a mathematical expression * and have the program calculate its values.
* *A two step process is used. Given a mathematical expression, a "build"
* method creates a binary expression tree representing the expression. It may
* be useful to think of the expression tree as the compiled version of the
* expression. Then
* an evaluate method is used to evaluate the binary expression tree. For
* example, the following code could be used in a simple situation to evaluate
* expression using the variables t, x, and y:
*
*
ExprEvaluator evaluator = new ExprEvaluator( );
*
double t = ...
*
double x = ...
*
double y = ...
*
String expression = ...
*
try {
*
evaluator.buildFromInfix(expression);
*
double value = evaluator.evaluate(t, x, y);
*
} catch (Exception e) {
*
...
*
}
*
*
All calculations are carried out with double precision real numbers.
* *If you are interested in handling multiple expressions, buildFromInfix * returns the expression tree (the "compiled" version of the expression). * This allows handling multiple expressions. See the "Evaluating multiple * infix expressions" section below. * *
The class provides "build" methods that can handle prefix, infix and * postfix expressions. Those expressions may contain the following:
*There are separate build methods for prefix, infix, and postfix expressions. * (If you are not familiar with these terms, we normally write mathematical * expressions in infix. Postfix is sometimes called reverse Polish notation and * is used by HP calculators and is convenient for computer work. You don't * need to know how to use prefix and postfix to use this class. You will probably * only want to use infix.) The following table show the equivalent prefix, infix, * and postfix for some expressions emphasizing notation for functions and "=" * signs.
*Prefix | Infix | PostFix | *
---|---|---|
/ + x y - t 7 | (x+y)/(t-7) | x y + t 7 - / | *
= x 4 | x = 4 | x 4 = | *
= a = b = c * x y | a = b = c = x * y | a b c x y * = = = | *
sin x | sin(x) | x sin | *
abs - x y | abs(x - y) | x y - abs | *
max x y | max(x, y) | x y max | *
* The "=" operator is optional and can be used in multiple assignments. For * example: Both x + y and z = x + y (or + x y and * = z + x y in prefix and x y + and z x y + = in * postfix) return the same value. They differ in second expression also sets * the value of z. The expression a = b = c = 3*x (or * = a = b = c * 3 x in prefix and a b c 3 x * = = = in * postfix) sets the values of a, * b and c in addition to returning the value of 3*x * (* 3 x in prefix). *
* Order of evaluation for infix expressions (the same as standard algebra and * Visual Basic) *
( ) | Parenthesized expressions (highest priority) | *
functions | * |
^ | exponentials (right associative: 2^3^4 = 2^(3^4) ) | *
leading + - | (as in -5) | *
* / | * |
binary + - | (as in 4 - 3) | *
= | assignment (right associative: value on right is assigned to * variable on left)) (lowest priority) | *
* To simplify using ExprEvaluator, it "remembers" the last expression tree
* created by a build method. That expression tree is the default for
* the evaluate methods. Depending on the variables used, there are three
* general ways of evaluating expressions after the tree is built:
*
Only the "common" variables t, x, and y are used:
*
Use double evaluate(double t, double x, double y).
*
Example: evaluator.evaluate(10, 20, 30);.
*
See the above coding example or
* TrivialExample.java.
*
*
Only a few variables are used but they include "uncommon" variables:
*
Use setValueOf(char var, double value) as needed to set values
* of variables
* and then use evaluate( ). For example, if the expression uses variables
* a and b:
*
evaluator.setValueOf('a', 10);
*
evaluator.setValueOf('b', 20);
*
try {
*
result = evaluator.evaluate( );
*
} catch (Expression e) {
*
...
*
}
*
See TrivialExample3.java.
*
*
Many variables with values stored in an array:
*
Use evaluate(double[] values).
*
Example:
*
double [] variables = new double[26];
*
...
*
result = root.evaluate(variables);
*
See TrivialExample2.java.
*
*
Notes:
*
* These techniques are not mutually exclusive. Internally, the same
* array is used to store variable values and is independent of the
* evaluate method is used. For example: Consider the sequence
*
evaluator.evaluate(10, 20, 30);
*
evaluator.evaluate( );
*
The second evaluate would use the values of t, x, and y resulting from
* the first evaluation. Typically, they would be t = 10, x = 20, and y = 30
* but it is possible that those values were changed during the course of the
* first call to evaluate.
*
* As another example, suppose that the expression is function that must be
* evaluated for many (x, y) pairs but depends on "constants" a and b. We could
* proceed as follows:
*
evaluator.setValueOf('a', 20);
*
evaluator.setValueOf('b', 30);
*
... inside a loop ...
*
xval = ...;
*
yval = ...;
*
value = evaluator.evaluate(0, xVal, yVal); // t is not used
*
* Evaluating multiple infix expressions
*
*
ExprEvaluator has special methods that are useful when processing multiple * infix expressions. *
* Evaluating functions for 2-D graph or table typically has one of the * following levels of difficulty: *
Type of problem | *Comment | *
---|---|
Evaluate or plot f(x) | *The buildFromInfix and zero parameter evaluate method are completely * capable of handling this situation. * See TableExample1.java * Alternatively, one may choose to use the buildFromInfix and evaluate(ExprTree) * methods as suggested in the next item. | *
Evaluate or plot multiple functions of x | *Assuming exprStr is string with the expression and valX is a double, use
* ExprTree expr = buildFromInfix(exprStr); * setX(valX); * double val = evaluate(expr);. * See TableExample2.java |
*
Use parametric functions for x and y. * (There may be multiple sets of expressions.) |
* Use the technique from the previous example except use the buildFromInfix * to build a tree for each x and y expression, set the value of the parameter, * and then use evaluate for each of the expression trees to get the x and y values. * See TableExample3.java | *
Use polar coordinates. * (There may be multiple sets of expressions.) |
* ExprEvaluator provides a special method, convertToRect(r, theta), to * convert polar * coordinates to rectangular coordinates that may be needed to graph polar * functions. If there is only 1 expression to be evaluated, then the * buildFromInfix, setValueOf, and the * zero parameter evaluate methods along with the convertToRect * method are completely capable of handling this situation. * However, if there is more than * one expression to be evaluated, you should use buildFromInfix for each expression, * set the values of the parameter(s) and then use evaluate(ExprTree) * methods for each expression being evaluated. * See TableExample4.java | *
While these techniques are designed for producing 2-D graphs, they may also * be useful in other situations where it is desired to evaluate multiple * functions. In fact, all the above examples just produce tables that could * be used for plotting but there could be other uses as well. *
* The general code format when using multiple infix functions:
*
*
ExprEvaluator evaluator = new ExprEvaluator();
*
double x;
*
double firstX = ...;
*
double lastX = ...;
*
double incX = ...;
*
double y1, y2;
*
ExprTree tree1, tree2;
*
String expr1 = ...;
*
String expr2 = ...;
*
try {
*
tree1 = evaluator.buildFromInfix(expr1);
*
tree2 = evaluator.buildFromInfix(expr2);
*
for (x = firstX; x < lastX; x += incX) {
*
evaluator.setX(x);
*
y1 = evaluator.evaluate(tree1);
*
y2 = evaluator.evaluate(tree2);
*
...
*
}
*
} catch (Exception e) {
*
...
*
}
*
*
*
The ExprEvaluator can evaluate 34 functions, including 32 functions * defined in Java's Math class, one unique function inspired by Excel * (roundTo(val, num)) and * a user defined function. You can search Java documentation for definitions * of functions that you are unfamiliar with. * The functions that can be used include the following: *
The buildFromInfix method allow the user to define
* a function with 0 to 10 parameters. Because of notational difficulties,
* the buildFromPrefix and buildFromPostfix methods only allow defining 1
* parameter functions. The formats for the string defining
* the function are
*
prefix: define = user parameter prefixExpression
*
infix: define user(parameter list) = infixExpression
*
postfix: define parameter user postfixExpression =
*
*
For example using infix: *
* try { * evaluator.buildFromInfix("define user(a, b, x) = x * max(a, b)"); * evaluator.setX(10); * evaluator.setY(20); * evaluator.setValueOf('z', 30); * evaluator.buildFromInfix("100000 + user(x, y, z)"); * double value = evaluator.evaluate(); * } catch (...) { * ... * } ** The following examples compare defining a function in prefix, infix, * and postfix: *
* When a build method is used to define a function, the resulting tree is * null and it returns null. The parameters follow the same notational rule * as variables: one lower case letter. * Once defined, the number of parameters is fixed (until user is redefined). * The expression used in defining a function can use parameters, * constants and any other variables and functions. * *
When the user function is defined using buildFromPrefix or * buildFromPostfix, it must have exactly 1 parameter. However, * once defined, the user function can be used in prefix, infix and postfix * expressions no matter which of the build functions was used to define it. * This is true independently of the number of parameters the function has. * (See TrivialExample4.java.) * *
The roundTo(x, num) function was inspired by the fact that Java often * prints doubles with many decimal places. For example, we might see * something like 1.5999999999 or 1.600000003 as approximations for 1.6 after * a series of calculations. The function was modeled after the * ROUND(number, num_digits) function in Excel. 'num' is the number of decimal * places to which x is rounded. If num < 0, then the number is rounded to the * left of the decimal point. For example, roundTo(12345.6,-3) = 12000.
** The roundTo function is available both when running ExprEvaluator and as * a public static function in the EasyFormat class. * *
The toPrefix(), toInfix(U) and toPostfix() methods allow converting from * one "..fix" to another after using any of the build... methods. toInfix() provides * fully parenthesized output. (I.e. typically there are many unneeded pairs * of parenthesis. For Example. x+y*z will be output as (x+(y*z)) .)
* *Illegal calculations such as 1/0, log(-1) or sqrt(-1) will typically * result in infinity, -infinity, or NaN as is normal in Java.
* *Beta 3: Modified for more efficient evaluations by adding fields to the * binary nodes to avoid having to repeatedly check for values, types, and * so on. Also ignores leading (unary) + signs. *
*Beta 4.0: Modified to allow variables a, b, ..., z. *
Beta 4.1: Added the public static function roundTo
*
Allow = sign as a right associative operator.
*
Added the function roundTo(x, numDecPlaces)
*
Changed the name of the class for ExpressionTree to ExprEvaluator
*
Implemented buildFromPrefix.
*
Beta 4.2: Added help messages for infix function and used * EasyFormat.roundTo. *
Beta 4.3: Added methods that were previously in the subclass * GraphEvaluator2D. *
Beta 4.4: Added many new functions. *
Beta 4.5: Added user defined function (and report error method), * added help for prefix and postfix. *
Beta 5.0: Implemented the toInfix() method and added TrivialExample5 * to test it. *
Beta 6.0: Added roundTo(x, num) as a public static method so it can * be used in ap or applet similar to the way Math.sqrt is used. * It is actually the same as EasyFormat.roundTo(x, num). *
*
* In the documentation for individual Fields, Constructors, and Methods, "##"
* is used to signify the item is intended primarily for use with aps. Some
* of the other items are public because of various requirements or possible
* extensions or debugging.
*/
public class ExprEvaluator {
private final static int MAX_PARAMS = 10;
/** ## The number PI = 3.14159... */
public static double PI = Math.PI;
/** ## The number E = 2.718... */
protected static double E = Math.E;
/** A String holding the 26 variables "a" to "z" allowed in Expression tree and
* 10 parameters allowed in the user function. The parameters follow the
* variables. Parameter names are either unprintable or have strange values.
* they are (char)123, (char)124, ..., (char) 132. The parameters
* are stored in reverse order so the parameter represented by (char)123 is always
* the last parameter.
*/
public static final String variables = "abcdefghijklmnopqrstuvwxyz"
+ (char)123 + (char)124 + (char)125 + (char)126 + (char)127
+ (char)128 + (char)129 + (char)130 + (char)131 + (char)132;
/** The allowed delimiters (operators). */
public String DELIMITERS = "+-*/^()=,";
// The operators. Note: > is used only internally. The constant is not
// used but included here for reference
// private String OPERATORS = DELIMITERS + "<";
/** The root of the current expression tree */
protected BinaryNode (Note: if the DoubleScanner is used, number tokens cannot begin
* with + or -.)
* @return true if the string is an operator, false otherwise.
*/
public static boolean isDouble(String s) {
char ch;
ch = s.charAt(0);
if ( Character.isDigit(ch)
|| (ch == '.' || ch == '-' || ch == '+') && (s.length() > 1))
{
try { // make sure that s can be converted to double
Double.parseDouble(s);
} catch ( Exception e ) {
return false;
}
return true;
} else
return false;
} // end isDouble
// ***************************** isOperator **************************
/**
* Determines if the string is an operator. Recognized operators are
* '(', ')', '+', '-', '*', '/', '^', '=', and ','. "," is allowed
* only in functions used in infix expressions.
*
* Actually this routine should be called isDelimiter as it only recognizes
* the operators that can be used in expressions.
*
* @return true if the string is an operator, false otherwise.
*/
public boolean isOperator(String s) {
// Note: IsOperator would more correctly called isDelimitor. The "operators"
// "<" and "[" are used internally but not recognized by this function.
int len;
char ch;
ch = s.charAt(0);
len = s.length();
return len == 1 && DELIMITERS.indexOf(ch) >= 0;
} // end isOperator
// **************************** isFunction **************************
/**
* Returns a number >= 0 if the string s is a function name. Returns
* -1 if it is not a function name. The value is the subscript of the
* function name in the array of function names.
* @param s - the string which will be tested.
* @return - the subscript of the function in the array of functions
* names or -1 if the string is not a function.
*/
public static int isFunction(String s) {
for (int i = 0; i < functions.length; i++) {
if (s.equals(functions[i]))
return i;
}
return -1;
} // end isFunction
// **************************** numFuncParams **************************
/**
* Returns the number of parameters if the string is a function name.
* See functions for a list of function names that will be recognized.
* Returns the number of parameters for the function or -1 if the string
* is not a function name.
* @param s - the string which will be tested.
* @return - the number of parameters if the string is the name of a
* function or -1 if the string is not a function.
*/
public static int numFuncParams(String s) {
for (int i = 0; i < functions.length; i++) {
if (s.equals(functions[i]))
return numParams[i];
}
return -1;
} // end numFuncParams
// **************************** precedence **************************
/**
* Determines the precedence of an operator.
*
* @param operator - the operator.
*
* @return the precedence of the operator.
*/
public static int precedence(String operator) {
if (operator.length() != 1)
return -10;
else if ("+-".indexOf(operator) >= 0)
return 4;
else if ("*/".indexOf(operator) >= 0)
return 5;
else if (operator.equals("^"))
return 6;
else if (operator.equals("("))
return -1;
else if (operator.equals("="))
return 1;
else if (operator.equals(")"))
return 0;
else if (operator.equals(",")) // parameter
return 2;
else if (operator.equals("<")) // function (
return 3;
else
return -10;
} // method precedence
// ************************** comparePrecedence **********************
/**
* Compares precedence of two operators.
*
* @param op1 the first operator.
* @param op2 the second operator.
*
* @return a negative number if op1 < op2, 0 if op1 = op2, or a
* positive number if op1 > op2. Special cases: if op1
* = "op2" = "^" or op1 = op2 = "=" then it returns -1 to cause
* "^" and "=" to be right associative.
*/
public static int comparePrecedence(String op1, String op2) {
if ((op1.equals("^") && op2.equals("^"))
|| (op1.equals("=") && op2.equals("=")))
return -1; // right associative so 2^3^2 = 2^(3^2)\
// and a = b = c is a = (b = c)
return precedence(op1) - precedence(op2);
} // method comparePrecedence
// ************************** showStacks *****************************
/**
* Optionally show the current token and the stacks. May be helpful
* for debugging or demonstrating how the procedure works.
* @param token - the token that was just processed.
* @param nodeStack - the node stack
* @param operatorStack - the operator stack
*/
private void showStacks(String token, ArrayPureStack Examples of postfix functions:
* The tree built from the prefix string is assigned to root.
*
* @param prefix the infix string to be processed.
* @return the expression tree that was built. This may be considered the
* "compiled" version of the expression.
*/
public ExprTree buildFromPrefix(String prefix) throws Exception {
boolean definingFunction = false; // <<<<<<<<<<<<<<<
BinaryNode The precedence of operators:
* The tree built from the infix string is assigned to root.
*
* @param infix the infix string to be processed.
* @return the expression tree that was built. This may be considered the
* "compiled" version of the expression.
* @throws Exception - if an identifier name is invalid or the expression
* is invalid.
*/
public ExprTree buildFromInfix(String infix) throws Exception{
DoubleScanner scan;
String token;
BinaryNode Examples of postfix functions:
* The tree built from the postfix string is assigned to root.
*
* @param postfix the postfix string to be processed.
* @return the expression tree that was built. This may be considered the
* "compiled" version of the expression.
*/
public ExprTree buildFromPostfix(String postfix) throws Exception
// throws ArrayIndexOutOfBoundsException
{
DoubleScanner scan;
String token;
BinaryNode
* In the case of illegal calculations such as 1/0, log(-1), or sqrt(-1),
* the result will typically be infinity, -infinity, or NaN (Not a Number).
* Note: This version assumes the values of the 26 values are unchanged
* from the last evaluation or the time they were supplied. If they have
* never been defined, their value will be 0.
*
* @return The value of the expression.
* @throws Exception - if a function cannot be evaluated or has the wrong
* number of parameters.
* @see #setT(double)
* @see #setX(double)
* @see #setY(double)
* @see #setValueOf(char, double)
* @see #setValues(double[])
*/
public double evaluate () throws Exception {
if (debug)
System.out.println("\nEvaluate");
if (root != null)
return evaluateSub(root);
else
return 0; // There is no tree to evaluate
} // end evaluate (3 parameter)
// ************************* evaluate (3 parameter) **********************
/**
* ## Returns the value of a binary expression tree previously created by
* one of the build methods using the supplied values of t, x, and y and the
* current values of the other variables. Once a binary tree is created by
* a build method, evaluate can be called repeatedly with different
* parameters.
*
* In the case of illegal calculations such as 1/0, log(-1), or sqrt(-1),
* the result will typically be infinity, -infinity, or NaN (Not a Number).
*
* Note: This version allows setting the values of the variables "t", "x",
* and "y". This may be completely adequate for many situations.
* The values of the other 23 variables are unchanged from any
* previous evaluations. If they have never been defined, there value will
* be 0.
*
* @param t - value of variable t.
* @param x - value of variable x.
* @param y - value of variable y.
* @return The value of the expression.
* @throws Exception - if a function cannot be evaluated or has the wrong
* number of parameters.
*/
public double evaluate (double t, double x, double y) throws Exception {
values['x' - 'a'] = x;
values['y' - 'a'] = y;
values['t' - 'a'] = t;
return evaluate();
} // end evaluate (3 parameter)
// *********************** evaluate (1 parameter) *************************
/**
* ## Returns the value of a binary expression tree previously created by
* one of the build methods using the supplied parameters. Once a binary
* tree is created by a build
* method, evaluate can be called repeatedly with different parameters.
*
* In the case of illegal calculations such as 1/0, log(-1), or sqrt(-1),
* the result will typically be infinity, -infinity, or NaN (Not a Number).
*
* In this version of evaluate, the values of all 26 variables are supplied
* in an array.
* @param params - an array of 26 double values corresponding to the
* values of variables "a", "b", ..., "z"
* @return The value of the expression.
* @throws Exception - if a function cannot be evaluated or has the wrong
* number of parameters.
* @see #getValues
*/
public double evaluate (double [] params) throws Exception {
setValues(params);
// for (int i = 0; i < Math.min(26, params.length); i++)
// values[i] = params[i];
return evaluate();
} // end evaluate (1 parameter)
private double evaluateSub(BinaryNode
* Use set... functions to assign values to variables before calling this
* methods.
* @param tree - the ExprTree to be evaluated.
* @return - the value of the expression which generated the ExprTree.
* @throws Exception - if a function cannot be evaluated or has the wrong
* number of parameters.
* @see #setX
* @see #setY
* @see #setT
* @see #setValueOf
* @see #setValues
* @see #evaluate
*/
public double evaluate(ExprTree tree) throws Exception {
root = tree.getTree();
return evaluate();
} // end 1 parameter evaluate
// ************************** convertToRect ***********************
/**
* ## Converts polar coordinates into rectangular coordinates. The results are
* stored in the variables "x" and "y". The other 24 variables remain
* unchanged. The getX and getY methods can be used to retrieve the values.
* @param r - the radius in polar coordinates.
* @param theta - the angle in polar coordinates. It is measured in radians.
* @see #getX
* @see #getY
* @see #getValueOf
*/
public void convertToRect(double r, double theta) {
values['x' - 'a'] = r * Math.cos(theta);
values['y' - 'a'] = r * Math.sin(theta);
} // end convertToRect
// ***************************** toString *****************************
/**
* Output the tree structure -- used in testing/debugging.
* Source: A modification of showStructure() in Data Structures
* *** in C++ by Roberge.
* @return String repression of the expression tree.
*/
public String toString () {
// Outputs the keys in a binary search tree. The tree is output
// rotated counterclockwise 90 degrees from its conventional
// orientation using a "reverse" inorder traversal. This operation is
// intended for testing and debugging purposes only.
if ( root == null )
return("Empty tree\n");
else
return "\n" + toStringSub(root,1) + "\n";
} // end toString
private String toStringSub ( BinaryNode
* ExprEvaluator.introHelp + ExprEvaluator.varHelp
* + ExprEvaluator.infixHelp
* @see #varHelp
* @see #prefixHelp
* @see #infixHelp
* @see #postfixHelp
*/
public static String introHelp =
"Expressions may include:";
/**
* ## varHelp can be used as the middle part of a help message in those
* situations where all 26 variables can be used. It would normally
* be immediately preceded infixHelp. In those situations where only
* a restricted subset of variables are allowed, use an appropriate
* substitute for this string listing those variables.
* @see #introHelp
* @see #prefixHelp
* @see #infixHelp
* @see #postfixHelp
*/
public static String varHelp =
" variables: a, b, c, ..., z\n";
private static String common1Help =
" double numbers (like 2 or 3.1415927)\n"
+ " constants: PI, E\n"
+ " operators: +, -, *, /, ^ (exponent), = (assignment)\n";
private static String common2Help =
"Notes:\n"
+ " Variable, constant, and function names are case sensitive.\n";
private static String common3Help =
" Trig functions use radians.\n"
+ " log uses base e while log10 uses base 10.\n"
+ " floor rounds down towards -infinity while round rounds"
+ " the nearest integer.\n";
private static String common4Help =
" random generates a random number >= 0 and <1.\n";
private static String common5Help =
" toDegrees and toRadians convert between degrees and"
+ " radians.\n"
+ " In addition to those functions listed, all Java functions"
+ " are available. (34 in total.)";
/**
* ## prefixHelp can be used in a help message that explains to the user
* what is allowed as input to the ExprEvaluator when prefix expressions
* are used. It should be preceded by introHelp and varHelp or
* equivalent customized for a particular applications.
*
* ExprEvaluator.introHelp + ExprEvaluator.varHelp
* + ExprEvaluator.prefixHelp
* @see #introHelp
* @see #varHelp
*/ public static String prefixHelp =
common1Help
+ " functions: e.g. abs x, acos x, asin x, atan x, atan2 y x, cos x,"
+ " cbrt x, ceil x, \n"
+ " cosh x, exp x, expm1 x, floor x, hypot x y, IEEEremaider x y,"
+ " log x, log10 x, \n"
+ " log1p x, max x y, min x y, pow x y, random, rint x, round x,"
+ " roundTo x num, \n"
+ " signum x, sin x, sinh x, sqrt x, tan x, tanh x, toDegrees x, toRadians x,\n"
+ " ulp x, or user x. [To define user use "
+ "\"define = user param expression\"].\n"
+ "\n"
+ common2Help
+ " = = a b + * 2 x 3 assigns values to a and b as well as"
+ " returning a value.\n"
+ common3Help
+ " roundTo x num rounds x to num decimal places. num<0 is OK.\n"
+ common4Help
+ " pow x y raises x to the y and is equivalent to ^ x y.\n"
+ common5Help;
/**
* ## infixHelp can be used in a help message that explains to the user
* what is allowed as input to the ExprEvaluator when infix expressions
* are used. It should be preceded by introHelp and varHelp or
* equivalent customized for a particular applications.
*
* ExprEvaluator.introHelp + ExprEvaluator.varHelp
* + ExprEvaluator.infixHelp
* @see #introHelp
* @see #varHelp
*/
public static String infixHelp =
common1Help
+ " functions: e.g. abs(x), acos(x), asin(x), atan(x), atan2(y, x),"
+ " cbrt(x), ceil(x), cos(x),\n"
+ " cosh(x), exp(x), expm1(x), floor(x), hypot(x, y), "
+ " IEEEremainder(x, y), log(x), log10(x), \n"
+ " log1p(x), max(x, y), min(x, y), pow(x, y), random(),"
+ " rint(x), round(x), roundTo(x, num),\n"
+ " signum(x), sin(x), sinh(x), sqrt(x), tan(x), tanh(x), toDegrees(x),"
+ " toRadians(x), ulp(x),\n"
+ " or user(...). [To define user use "
+ "\"define user(paramList) = expression)\"].\n"
+ "\n"
+ common2Help
+ " \"^\" is right associative so 4^3^2 = 4^(3^2).\n"
+ " Leading - signs are treated as binary operators."
+ " That is, -x is interpreted as 0 - x.\n"
+ " Leading + signs are ignored.\n"
+ " a = b = 2 * x + 3 assigns values to a and b as well as"
+ " returning a value.\n"
+ common3Help
+ " roundTo(x, num) rounds x to num decimal places. num<0 is OK."
+ "\n"
+ common4Help
+ " pow(x, y) raises x to the y and is equivalent to x ^ y.\n"
+ common5Help;
/**
* ## postfixHelp can be used in a help message that explains to the user
* what is allowed as input to the ExprEvaluator when postfix expressions
* are used. It should be preceded by introHelp and varHelp or
* equivalent customized for a particular applications.
*
* ExprEvaluator.introHelp + ExprEvaluator.varHelp
* + ExprEvaluator.postHelp
* @see #introHelp
* @see #varHelp
*/ public static String postfixHelp =
common1Help
+ " functions: e.g. x abs, x acos, x cosh, x asin, x atan,"
+ " y x atan2, x cbrt, x ceil,\n"
+ " x cos, x cosh, x exp, x expm1, x floor, x y hypot,"
+ " x y IEEEremainder, x log, \n"
+ " x log10, x loglp, x y max, x y min,"
+ " x y pow, random, x rint, x round, x num roundTo,\n"
+ " x signum, x sin, x sinh, x sqrt, x tan,"
+ " x tanh, x toDegrees, x toRadians,\n"
+ " x ulp or x user. [To define user use "
+ "\"define param user expression = \"].\n"
+ "\n"
+ common2Help
+ " a b 2 x * 3 + = = assigns values to a and b as well as"
+ " returning a value.\n"
+ common3Help
+ " x num roundTo rounds x to num decimal places. num<0 is OK.\n"
+ common4Help
+ " x y pow raises x to the y and is equivalent to x y ^.\n"
+ common5Help;
// **************************** CONSTRUCTOR ****************************
/**
* ## Initializes an ExprEvaluator object with an empty expression tree.
*/
public ExprEvaluator () {
int i;
root = null;
for (i = 0; i < 26; i++)
values[i] = 0;
} // end ExprEvaluator
// **************************** debugMode **************************
/**
* Sets the debug mode in buildFromInfix. Debug output is produced
* and sent to System.out if the private variable debugStacks is true.
* The output is only useful for debugging build and evaluate methods.
* @param debugging - sets the debug mode (true turns the mode on).
*/
public void debugMode(boolean debugging) {
debug = debugging;
} // end debugMode
// ************************** displayStacks ************************
/**
* Sets the display stack mode in buildFromInfix. Output is produced
* and sent to System.out
* if the mode is true. This output may be useful to demonstrate how
* buildFromInfix uses stacks or to help while debugging.
* @param debug - sets the display stack mode (true turns the mode on.
*/
public void displayStacks(boolean debug) {
debugStacks = debug;
} // end debugMode
// ***************** get and sets for variables ********************
/**
* ## Gets the value of x.
* @return - the value of x used in the last call of evaluate.
* @see #setX(double)
*/
public double getX( ) {
return values['x' - 'a'];
} // end getX
/**
* ## Sets the value of x.
* @param value - the value of variable 'x'
* @see #getX
*/
public void setX(double value) {
values['x' - 'a'] = value;
}
/**
* ## Gets the value of y.
* @return - the value of y used in the last call of evaluate.
* @see #setY
*/
public double getY( ) {
return values['y' - 'a'];
} // end #getY
/**
* ## Sets the value of y.
* @param value - the value of variable 'y'
* @see #getY
*/
public void setY(double value) {
values['y' - 'a'] = value;
} // end of setY
/**
* ## Gets the value of t.
* @return - the value of t used in the last call of evaluate.
* @see #setT
*/
public double getT( ) {
return values['t' - 'a'];
} // end getT
/**
* ## Sets the value of t.
* @param value - the value of variable 't'
* @see #getT
*/
public void setT(double value) {
values['t' - 'a'] = value;
} // end setT
/**
* ## Gets the value of the variable var where var is 'a', 'b', ..., or 'z'.
* @param var - the variable name as a character.
* @return - the value of the specified variable. If the variable is outside
* the range of 'a', 'b', ..., 'z', NaN (Not a Number) is returned instead.
* @see #setValueOf
* @see #getX
* @see #getY
* @see #getT
*/
public double getValueOf(char var) {
if (var >= 'a' && var <= 'z')
return values[variables.indexOf(var)];
else
return Double.NaN;
} // getValueOf
/**
* ## Sets the value of the specified variable ('a', 'b', ..., or 'z') to
* the specified value. The value is ignored if the character var is
* outside the specified range.
* @param var - a character in the range 'a' to 'z'. The name of one of
* the 26 variables.
* @param value - the value to which the variable is set.
* @see #getValueOf
* @see #setX
* @see #setY
* @see #setT
*/
public void setValueOf(char var, double value) {
if (var >= 'a' && var <= 'z')
values[var - 'a'] = value;
}
/**
* ## Returns the array of 26 doubles corresponding to the the variables
* "a", "b", ..., or "z". The value of "a" is stored in location 0,
* the value of "b" is stored in location 1 and so on.
* @return - an array containing the values of the 26 variables.
* @see #setValues
*/
public double [] getValues() {
return values;
} // getValues
/**
* ## Sets the value of all 26 variables.
* @param values - an array of doubles with the 26 variable values. If the
* array has less than 26 values, only corresponding values are set. If
* array has more than 26 values, only the first 26 are used.
* @see #getValues
*/
public void setValues(double [] values) {
for (int i = 0; i < Math.min(values.length, 26); i++)
this.values[i] = values[i];
}
// **************************** getInputStr **********************
/**
* ## Returns the last input string processed by buildFromPrefix, buildFromInfix,
* or buildFromPostfix methods.
*
* @return = the last input string.
*/
public String getInputStr() {
return inputStr;
} // end getInputStr
// *************************** getUserFunction ********************
/**
* ## Returns the current user function as a string.
* @return The user function. It will be the empty string if the function
* has not been defined properly.
*/
public String getUserFunction() {
return userFunction;
}
// ***************************** isDouble **************************
/**
* Determines if the string is an double. Numbers begin with a digit
* or a '.', "+", or "-". Strings beginning with a nondigit must
* be longer than one character. Values passing these tests are
* parsed to make sure they will convert to a double.
*
sqrt 16 : (square root of 16)
*
* sqrt + ^4 2 ^ 3 2 100 : (square root(4^2 + 3^2) * 100)
*
toDegrees atan2 1 sqrt 3 : (atan2(1, sqrt(3)) converted to
* degrees)
*
*
*
*
*
* subtree expression for function
* /
* =
* \
* subtree function name and parameters
*
* The following actions take place:
* Some error checking is done
* The parameters are replaced by "unique variables"
* The subtree for the function is used as the function definition
* @param root - The root of a tree defining the user function having
* the form specified above.
* @throws - Exception if the root of the tree is not "=", the name of the
* function in the left subtree is not "user", there is an illegal
* parameter, a parameter name is repeated in the paramter list,
* or there are two many parameters.
*/
protected void defineFunction(BinaryNode
16 sqrt : (square root of 16)
*
4 2 ^ 3 2 ^ + sqrt 100 * : (sq root(4^2 + 3^2) * 100)
*
1 3 sqrt atan2 toDegrees : (atan2(1, sqrt(3)) converted to
* degrees)
*
*