/*
* Use the JavaScript Engine to employ calls to the eval() function.
* This is much simpler than writing a full formula parser and lexer
* with the capacity to tokenize, substitute, and evaluate general
* mathematical expressions.
*
* Session example:
* Enter a formula.
* (y-3.25) / x
* Enter the value of the variable x:
* 10.35
* Enter the value of the variable y:
* 13.6
* formula: (y-3.25) / x
* with variables:
* x = 10.35
* y = 13.6
* translates to: (13.6-3.25) / 10.35 and
* evaluates to: 1.0
*/
import java.util.Hashtable;
import java.util.Scanner;
import java.util.Map.Entry;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class FormulaEvaluator
{
public static void main( String[] args ) {
// Scanner to collect user input
Scanner scan = new Scanner(System.in);
// prompt user for formula string
System.out.println( "Enter a formula.");
String formula = scan.nextLine();
// variables will be presumed to be single, lower-case
// alphabetical characters - kill everything else
String variables = kernel(
formula.replaceAll( "[^a-z]", "" )
);
// to collect values or each variable
String[] values = new String[ variables.length() ];
// for each lower-case variable name, collect value
for (int i = 0; i < variables.length(); i++) {
System.out.println(
"Enter the value of the variable " +
variables.charAt( i ) + ": "
);
values[ i ] = scan.next();
}
// copy original formula
String evaluable = formula;
// substitute the corresponding value for each variable
// in the original formula
for (int i = 0; i < variables.length( ); i++) {
evaluable = evaluable.replaceAll(
"" + variables.charAt( i ), values[ i ]
);
}
// get script engine manager instance
ScriptEngineManager manager = new ScriptEngineManager();
// javascript engine instance to use for evaluation, since
// math ops are mostly the same
ScriptEngine engine = manager.getEngineByName("js");
Object result = null;
try {
result = engine.eval( evaluable );
} catch (ScriptException e) {
System.out.println( e.toString() );
}
// compose output to report
String rpt = "formula: " + formula + "\nwith variables:";
for (int i = 0; i < variables.length( ); i++) {
rpt += "\n " + variables.charAt( i ) + " = " +
values[ i ];
}
rpt += "\ntranslates to: " + evaluable + " and " +
"\nevaluates to: " + String.valueOf( result );
System.out.println( rpt );
}
// Return unique elements of a on first dimension.
public static String kernel( String s ) {
// Set hashtable style associative array working storage.
Hashtable
r = new Hashtable();
// For each element in s...
for (int i = 0; i < s.length(); i++) {
// ...assign key/value pair - repeated values have same key and
// replace one another, leaving only single instance of value.
r.put("" + s.charAt( i ), "" + s.charAt( i ));
}
// Initialize return.
StringBuffer sb = new StringBuffer();
// For each key in r...
for (Entry entry : r.entrySet()) {
sb.append( entry.getKey() );
}
return sb.toString();
};
}
UPDATE:
It occurred to me that you might get formulas with more than one instance of a particular variable,e.g., (x+y)/x. So, I added a step that makes sure you only ask for the value of each variable once.
ADDED:
Java version more prettily formatted at http://pastebin.com/sJYnSh5i
HTML/JavaScript version at http://pastebin.com/Q5hHyhMn