Solution for
Programming Exercise 9.4
THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to
the following exercise from this on-line
Java textbook.
Exercise 9.4:
The file Expr.java defines
a class, Expr, that can be used to represent mathematical
expressions involving the variable x. The expression can
use the operators +, -, *, /, and ^, where ^ represents the operation
of raising a number to a power. It can use mathematical functions
such as sin, cos, abs, and ln.
See the source code file for full details. The Expr class
uses some advanced techniques which have not yet been covered in this
textbook. However, the interface is easy to understand. It contains
only a constructor and two public methods.
The constructor new Expr(def)
creates an Expr object defined by a given expression. The parameter,
def, is a string that contains the definition. For
example, new Expr("x^2") or new Expr("sin(x)+3*x").
If the parameter in the constructor call does not represent a legal
expression, then the constructor throws an IllegalArgumentException.
The message in the exception describes the error.
If func is a variable of type Expr and
num is of type double, then
func.value(num) is a function
that returns the value of the expression when the number num
is substituted for the variable x in the expression.
For example, if Expr represents the expression 3*x+1,
then func.value(5) is 3*5+1, or 16.
If the expression is undefined for the specified value of x,
then the special value Double.NaN is returned.
Finally, func.getDefinition()
returns the definition of the expression. This is just the string
that was used in the constructor that created the expression object.
For this exercise, you should write a program that lets the
user enter an expression. If the expression contains an error,
print an error message. Otherwise, let the user enter some
numerical values for the variable x. Print the value
of the expression for each number that the user enters. However,
if the expression is undefined for the specified value of x,
print a message to that effect. You can use the boolean-valued
function Double.isNaN(val) to check whether a number,
val, is Double.NaN.
The user should be able to enter as many values of x as
desired. After that, the user should be able to enter a new expression.
Here is an applet that simulates my solution to this exercise, so that
you can see how it works:
Discussion
A pseudocode algorithm for the program is given by:
while (true):
Get a line of input from the user
if the line is empty:
break
Convert the input line to an Expr
Read and process the user's numbers
Converting the input line into an object of type Expr
involves calling the constructor from the Expr class. This
call might generate an IllegalArgumentException. The algorithm
must be expanded to handle this exception and print an error message if
it occurs. When an error occurs, I use a continue statement
to jump back to the start of the loop without reading any numbers from
the user:
while (true):
Get a line of input from the user
if the line is empty:
break
try {
Let expression = new Expr(line)
}
catch (IllegalArgumentException e) {
Print an error message
continue // jumps back to start of loop
}
Read and process the user's numbers
The last step, reading and processing the user's numbers, expands
into a loop, which is nested inside the main while loop.
In this loop, I could use TextIO.getDouble() to read one
of the user's numbers, but instead I choose to read the user's input
into a string and convert that string into a value of type
double. This has two advantages: I can end the loop when the
user presses return. And I can do nicer error handling than the default
error-handling that is provided by TextIO. The conversion from
a string, line, to a double is done using a method
that was introduced in Section 7.4. The conversion
will generate a NumberFormatException if the user's input is not
a legal number. The algorithm for reading and processing the user's
numbers becomes:
while (true):
Get a line of input from the user
if the line is empty:
break
try {
Let x = Double.parseDouble(line)
}
catch (NumberFormatException e) {
Print an error message
continue
}
Let val = expression.value(x)
if val is Double.NaN:
Print an error message
else:
Output val
All this can be easily translated into the complete solution, which follows.
The Solution
public class FunctionEvaluator {
public static void main(String[] args) {
String line; // A line of input read from the user.
Expr expression; // The definition of the function f(x).
double x; // A value of x for which f(x) is to be calculated.
double val; // The value of f(x) for the specified value of x.
TextIO.putln("This program will evaluate a specified function, f(x), at");
TextIO.putln("specified values of the variable x. The definition of f(x)");
TextIO.putln("can use the operators +, -, *, /, and ^ as well as mathematical");
TextIO.putln("functions such as sin, abs, and ln.");
while (true) {
/* Get the function from the user. A line of input is read and
used to construct an object of type Expr. If the input line is
empty, then the loop will end, and the program will terminate. */
TextIO.putln("\n\n\nEnter definition of f(x), or press return to quit.");
TextIO.put("\nf(x) = ");
line = TextIO.getln().trim();
if (line.length() == 0)
break;
try {
expression = new Expr(line);
}
catch (IllegalArgumentException e) {
// An error was found in the input. Print an error
// message and go back to the beginning of the loop.
TextIO.putln("Error! The definition of f(x) is not valid.");
TextIO.putln(e.getMessage());
continue;
}
/* Read values of x from the user, until the user presses return.
If the user's input is not a legal number, print an error message.
Otherwise, compute f(x) and print the result. */
TextIO.putln("\nEnter values of x where f(x) is to be evaluated.");
TextIO.putln("Press return to end.");
while (true) {
TextIO.put("\nx = ");
line = TextIO.getln().trim();
if (line.length() == 0)
break;
try {
x = Double.parseDouble(line);
}
catch (NumberFormatException e) {
TextIO.putln("\"" + line + "\" is not a legal number.");
continue;
}
val = expression.value(x);
if (Double.isNaN(val))
TextIO.putln("f(" + x + ") is undefined.");
else
TextIO.putln("f(" + x + ") = " + val);
} // end while
} // end while
TextIO.putln("\n\n\nOK. Bye for now.");
} // end main();
} // end class FunctionEvaluator
[ Exercises
| Chapter Index
| Main Index
]