PGnumericevaluators.pl - Macros that generate numeric answer evaluators.
ANS(num_cmp($answer_or_answer_array_ref, %options_hash));
ANS(std_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(std_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(std_num_cmp_list($relTol, $format, @answerList));
ANS(std_num_cmp_abs_list($absTol, $format, @answerList));
ANS(arith_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(arith_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(arith_num_cmp_list($relTol, $format, @answerList));
ANS(arith_num_cmp_abs_list($absTol, $format, @answerList));
ANS(strict_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(strict_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(strict_num_cmp_list($relTol, $format, @answerList));
ANS(strict_num_cmp_abs_list($absTol, $format, @answerList));
ANS(frac_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(frac_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(frac_num_cmp_list($relTol, $format, @answerList));
ANS(frac_num_cmp_abs_list($absTol, $format, @answerList));
Numeric answer evaluators take in a numerical answer, compare it to the correct answer, and return a score. In addition, they can choose to accept or reject an answer based on its format, closeness to the correct answer, and other criteria.
The general numeric answer evaluator is num_cmp(). It takes a hash of named options as parameters. There are also sixteen specific "mode"_num_cmp() answer evaluators for use in common situations which feature a simplified syntax.
The MathObjects system provides $obj->cmp() methods that produce answer evaluators for a wide variety of answer types. num_cmp() has been rewritten to use the appropriate MathObject to produce the answer evaluator. It is recommended that you use the MathObjects cmp() methods directly if possible.
ANS(num_cmp($answer_or_answer_array_ref, %options));
num_cmp() returns one or more answer evaluators (subroutine references) that compare the student's answer to a numeric value. Evaluation options are specified as items in the %options hash. This can make for more readable code than using the "mode"_num_cmp() style, but some people find one or the other easier to remember.
$answer_or_answer_array_ref can either be a scalar containing a numeric value or a reference to an array of numeric scalars. If multiple answers are provided, num_cmp() will return a list of answer evaluators, one for each answer specified. %options is a hash containing options that affect the way the comparison is performed. All hash items are optional. Allowed options are:
This determines the allowable methods for entering an answer. Answers which do not meet this requirement will be graded as incorrect, regardless of their numerical value. The recognized modes are:
The default mode allows any expression which evaluates to a number, including those using elementary functions like sin() and exp(), as well as the operations of arithmetic (+, -, *, /, and ^).
Only decimal numbers are allowed.
Only whole numbers and fractions are allowed.
Arithmetic expressions are allowed, but no functions.
Note that all modes allow the use of "pi" and "e" as constants, and also the use of "E" to represent scientific notation.
The format to use when displaying the correct and submitted answers. This has no effect on how answers are evaluated; it is only for cosmetic purposes. The formatting syntax is the same as Perl uses for the sprintf() function. Format strings are of the form '%m.nx' or '%m.nx#', where m and n are described below, and x is a formatter.
Esentially, m is the minimum length of the field (make this negative to left-justify). Note that the decimal point counts as a character when determining the field width. If m begins with a zero, the number will be padded with zeros instead of spaces to fit the field.
The precision specifier (n) works differently depending on which formatter you are using. For d, i, o, u, x and X formatters (non-floating point formatters), n is the minimum number of digits to display. For e and f, it is the number of digits that appear after the decimal point (extra digits will be rounded; insufficient digits will be padded with spaces--see '#' below). For g, it is the number of significant digits to display.
The full list of formatters can be found in the manpage for printf(3), or by typing "perldoc -f sprintf" at a terminal prompt. The following is a brief summary of the most frequent formatters:
%d decimal number
%ld long decimal number
%u unsigned decimal number
%lu long unsigned decimal number
%x hexadecimal number
%o octal number
%e floating point number in scientific notation
%f floating point number
%g either %e or %f, whichever takes less space
Technically, %g will use %e if the exponent is less than -4 or greater than or equal to the precision. Trailing zeros are removed in this mode.
If the format string ends in '#', trailing zeros will be removed in the decimal part. Note that this is not a standard syntax; it is handled internally by WeBWorK and not by Perl (although this should not be a concern to end users). The default format is '%0.5f#', which displays as a floating point number with 5 digits of precision and no trailing zeros. Other useful format strings might be '%0.2f' for displaying dollar amounts, or '%010d' to display an integer with leading zeros. Setting format to an empty string ( '' ) means no formatting will be used; this will show 'arbitrary' precision floating points.
An absolute tolerance value. The student answer must be a fixed distance from the correct answer to qualify. For example, an absolute tolerance of 5 means that any number which is +-5 of the correct answer qualifies as correct. abstol is accepted as a synonym for tol.
A relative tolerance. Relative tolerances are given in percentages. A relative tolerance of 1 indicates that the student answer must be within 1% of the correct answer to qualify as correct. In other words, a student answer is correct when
abs(studentAnswer - correctAnswer) <= abs(.01*relTol*correctAnswer)
tol and relTol are mutually exclusive. reltol is also accpeted as a synonym for relTol.
zeroLevel and zeroLevelTol specify a alternative absolute tolerance to use when the correct answer is very close to zero.
If the correct answer has an absolute value less than or equal to zeroLevel, then the student answer must be, in absolute terms, within zeroLevelTol of correctAnswer, i.e.,
abs(studentAnswer - correctAnswer) <= zeroLevelTol
In other words, if the correct answer is very near zero, an absolute tolerance will be used. One must do this to handle floating point answers very near zero, because of the inaccuracy of floating point arithmetic. However, the default values are almost always adequate.
A string representing the units of the correct answer. If specified, the student answer must include these units. The strings and units options are mutually exclusive.
A reference to an array of strings which are valid (but incorrect) answers. This prevents non-numeric entries like "NaN" or "None" from causing a syntax error. The strings and units options are mutually exclusive.
If set to 1, extra debugging information will be output.
# correct answer is 5, using defaults for all options
num_cmp(5);
# correct answers are 5, 6, and 7, using defaults for all options
num_cmp([5,6,7]);
# correct answer is 5, mode is strict
num_cmp(5, mode=>'strict');
# correct answers are 5 and 6, both with 5% relative tolerance
num_cmp([5,6], relTol=>5);
# correct answer is 6, "Inf", "Minf", and "NaN" recognized as valid, but
# incorrect answers.
num_cmp(6, strings=>["Inf", "Minf", "NaN"]);
# correct answer is "-INF", "INF" and numerical expressions recognized as
# valid, but incorrect answers.
num_cmp("-INF", strings => ["INF", "-INF"]);
There are 16 functions that provide simplified interfaces to num_cmp(). They are organized into four groups, based on the number of answers accpeted (single or list) and whether relative or absolute tolerances are used. Each group contains four functions, one for each evaluation mode. See the mode option to num_cmp() above for details about each mode.
GROUP:| "normal" | "list" | "abs" | "abs_list" |
| single answer | list of answers | single answer | list of answers |
MODE: | relative tol. | relative tolerance | absolute tolerance | absolute tolerance |
-------+----------------+---------------------+--------------------+-------------------------+
std | std_num_cmp | std_num_cmp_list | std_num_cmp_abs | std_num_cmp_abs_list |
frac | frac_num_cmp | frac_num_cmp_list | frac_num_cmp_abs | frac_num_cmp_abs_list |
strict | strict_num_cmp | strict_num_cmp_list | strict_num_cmp_abs | strict_num_cmp_abs_list |
arith | arith_num_cmp | arith_num_cmp_list | arith_num_cmp_abs | arith_num_cmp_abs_list |
The functions in each group take the same arguments.
ANS(std_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(arith_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(strict_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
ANS(frac_num_cmp($correctAnswer, $relTol, $format, $zeroLevel, $zeroLevelTol));
This group of functions produces answer evaluators for a single correct answer using relative tolerances. The first argument, $correctAnswer, is required. The rest are optional. The arguments are equivalent to the identically-named options to num_cmp(), above.
ANS(std_num_cmp_list($relTol, $format, @answerList));
ANS(arith_num_cmp_list($relTol, $format, @answerList));
ANS(strict_num_cmp_list($relTol, $format, @answerList));
ANS(frac_num_cmp_list($relTol, $format, @answerList));
This group of functions produces answer evaluators for a list of correct answers using relative tolerances. $relTol and $format are equivelent to the identically-named options to num_cmp() above. @answerList must contain one or more correct answers. A list of answer evaluators is returned, one for each answer provided in @answerList. All answer returned evaluators will use the relative tolerance and format specified.
ANS(std_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(arith_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(strict_num_cmp_abs($correctAnswer, $absTol, $format));
ANS(frac_num_cmp_abs($correctAnswer, $absTol, $format));
This group of functions produces answer evaluators for a single correct answer using absolute tolerances. The first argument, $correctAnswer, is required. The rest are optional. The arguments are equivalent to the identically-named options to num_cmp(), above.
ANS(std_num_cmp_abs_list($absTol, $format, @answerList));
ANS(arith_num_cmp_abs_list($absTol, $format, @answerList));
ANS(strict_num_cmp_abs_list($absTol, $format, @answerList));
ANS(frac_num_cmp_abs_list($absTol, $format, @answerList));
This group of functions produces answer evaluators for a list of correct answers using absolute tolerances. $absTol and $format are equivelent to the identically-named options to num_cmp() above. @answerList must contain one or more correct answers. A list of answer evaluators is returned, one for each answer provided in @answerList. All answer returned evaluators will use the absolute tolerance and format specified.
# The student answer must be a number in decimal or scientific notation
# which is within .1 percent of 3.14159. This assumes
# $numRelPercentTolDefault has been set to .1.
ANS(strict_num_cmp(3.14159));
# The student answer must be a number within .01 percent of $answer (e.g. #
3.14159 if $answer is 3.14159 or $answer is "pi" or $answer is 4*atan(1)).
ANS(strict_num_cmp($answer, .01));
# The student answer can be a number or fraction, e.g. 2/3.
ANS(frac_num_cmp($answer)); # or
ANS(frac_num_cmp($answer, .01));
# The student answer can be an arithmetic expression, e.g. (2+3)/7-2^.5 .
ANS(arith_num_cmp($answer)); # or
ANS(arith_num_cmp($answer, .01));
# The student answer can contain elementary functions, e.g. sin(.3+pi/2)
ANS(std_num_cmp($answer)); # or
ANS(std_num_cmp( $answer, .01));
ANS(numerical_compare_with_units($correct_ans_with_units, %options))
This function is deprecated. Use num_cmp with the units option instead:
ANS(num_cmp($correct_ans, units=>$units));
ANS(std_num_str_cmp($correctAnswer, $ra_legalStrings, $relTol, $format, $zeroLevel, $zeroLevelTol))
This function is deprecated. Use num_cmp() with the strings option instead:
ANS(num_cmp($correctAnswer, strings=>$ra_legalStrings, ...));