One of the main advantages of WeBWorK is that it can check open ended answers. Some of the basic types it can deal with are:
In each case, the ANS command is used to process the result of an answer evaluator. The correct answer can contain perl variables. You can (and often should) provide the answer as a string, even if it is to be evaluated as a number.
For example, if $a and $b contain values and we want to check for their average, the line would be
ANS( num_cmp( "($a+$b)/2" ) );
The basic answer evaluator for numbers is num_cmp
.
By default, it will do arithmetic for the student and evaluate
standard functions such as sin
and sqrt
.
ANS( num_cmp( "sqrt($a^2)+5 cos($b)" ));It is good to put the answer in double quotes as shown. Although many answers will be fine without the quotes, the difference is whether perl evaluates the expression immediately (no quotes), or whether WeBWorK gets a chance to fix up your entry (with quotes). Without quotes, the expression above would have two errors (without quotes, the implicit multiplication of 5 times the cosine value would have to be explicit, and the squaring would have to be written **2). Also with quotes, the student will see your answer as shown which gives an indication of the structure of the answer. In general, this is good.
Optional arguments to num_cmp
are given as
key/value pairs -- you specify the name of the option you want
to use and the new value for it. For example,
num_cmp
will accept answers within a certain
percentage of correct answer. To change this percentage to 0.2%
we would use:
ANS( num_cmp( "sqrt($a^2)+5 cos($b)", relTol=>0.2 ));If we would like to accept answers within 0.1 of the given answer, we would write
ANS( num_cmp( "sqrt($a^2)+5 cos($b)", tolType=> 'absolute', tol=>0.1 ));If we want a question where the answer might be a number or might be the word "none", we could first set $answer to be the right answer and then use
ANS( num_cmp( $answer, strings=>["none"] ));Regardless of whether $answer is "none" or 27.3, the word none will not generate a syntax error and the answer checking will function properly.
You can also specify a "mode" in the options. The default will
use floating point arithmetic, evaluating operations and
elementary functions along the way. If you don't want function
evaluation, set mode=>'arith'
. If you don't want
all arithmetic, but want to allow fractions, set
mode=>'frac'
. If you don't want any computation
and want to force the answer to be just a number, use
mode=>'strict'
.
These options (and more) can be mixed and matched to produce your desired result.
The basic way to check an answer which is a function is with
fun_cmp
. The answer should always be in quotes,
such as
ANS( fun_cmp( "x^3+2*x-1" ) );Here, multiplications must be given explicity by the instructor (but not the students). There are optional arguments here too. The most commonly used ones are as follows. If you want to specify a different variable, use
ANS( fun_cmp( "t^2 + t*sin(t)", var => 't') );or
ANS( fun_cmp( "x*y + x*sin(y)", var => ['x', 'y']) );Function comparison is done by comparing the value of the instructor's answer and the student's answer at points. If the answer has a limited domain, you should tell WeBWorK a range of values to sample from when comparing answers:
ANS(fun_cmp( "3*sqrt(x)*y", var => ['x', 'y'], limits => [[0,10], [-10,10]] ));For integration problems, you may want to check an answer up to addition of a constant. So, to check for an antiderivative of x^2, use
ANS( fun_cmp( "x^3/3", mode => 'antider') );In other cases, the answer might not be a single function, but any function in a family will do. If the parameters appear linearly in the expression, you can tell WeBWorK to allow that much freedom in checking the function. For example, to specify a quadratic polynomial with a double root at $a, use
ANS( fun_cmp( "c*(x-$a)^2", params => ['c']) );
The basic way to check a list of numbers is as follows:
ANS( number_list_cmp( "1, 4, 9, 16" ) );Again, the list has to be in quotation marks. It is ok for the list to have only one term to it. Individual values are checked using
num_cmp
, and all of its optional arguments can
be used here as well. In addition, there is one more optional
arguement. By default, number_list_cmp
does not
require that students specify their answers in the same order as
the instructor (for problems like, "Find the real roots of the
following function"). If you want to require the order to be the
same, use
ANS( number_list_cmp( "1, 4, 9, 16", ordered=>'strict' ) );
Again, the answer should be set as a string. A typical answer might be "(-infinity, 4]" or "(2, 3] U (7, 11)", which would be checked with
ANS( interval_cmp( "(2, 3] U (7, 11)" ) ); ANS( interval_cmp( "(-infinity, 4]" ) );respectively. Endpoints of intervals are either plus or minus infinity or a number. Numbers are checked using
num_cmp
, and any of the optional arguments to
num_cmp
can be used here. Infinity can be typed in a
variety of ways: infinity, infty, inf, and the checking is not
case sensitive. The union symbol is optional for both instructors
and students.
There are two additional optional arguments. By default, it
doesn't care in what order the student lists the intervals. If
you want to require the student to list them in the same order
the instructor did, add the option
ordered=>'strict'
.
By default, students have to get the
open/closed parts of endpoints right. In some
cases, you may not care about that part (e.g. some
people don't like to be fussy about it on
increasing/decreasing problems). To make it ignore
the difference between open (parens) and closed
(brackets), add the option sloppy=>'yes'
.
Ordered pairs, and lists of ordered pairs, can be checked by using the interval checker since "(2,5)" could denote either an open interval or an ordered pair.
The only difference comes up when you have a list of ordered pairs.
You would normally separate the entries with commas instead of union
symbols. To tell the interval checker that this is what you want,
include the option unions=>'no'
, as in
ANS( interval_cmp( "(2, 3), (7, 11)", unions=>'no' ) );
The work represented here was produced with partial support from a grant by the National Science Foundation (DUE-0125369).