From WeBWorK
NAME
contextCurrency.pl - Context for entering numbers with currency symbols and commas.
DESCRIPTION
This file implements a context in which students can enter currency values that include a currency symbol and commas every three digits. You can specify what the currency symbol is, as well as what gets used for commas and decimals.
To use the context, put
loadMacros("contextCurrency.pl");
at the top of your problem file, and then issue the
Context("Currency");
command to select the context. You can set the currency symbol and the comma or decimal values as in the following examples
Context()->currency->set(symbol=>'#');
Context()->currency->set(symbol=>'euro'); # accepts '12 euro'
Context()->currency->set(comma=>'.',decimal=>','); # accepts '10.000,00'
You can add additional symbols (in case you want to allow more than one way to write the currency). For example:
Context("Currency")->currency->addSymbol("dollars","dollar");
would accept '$12,345.67' or '12.50 dollars' or '1 dollar' as acceptable values. Note that if the symbol cantains any alphabetic characters, it is expected to come at the end of the number (as in the examples above) and if the symbol has only non-alphabetic characters, it comes before it. You can change this as in these examples:
Context()->currency->setSymbol(euro=>{associativity=>"left"});
Context()->currency->setSymbol('#'=>{associativity=>"right"});
You can remove a symbol as follows:
Context()->currency->removeSymbol('dollar');
To create a currency value, use
$m = Currency(10.99);
or
$m1 = Compute('$10.99');
$m2 = Compute('$10,000.00');
and so on. Be careful, however, that you do not put dollar signs inside double quotes, as this refers to variable substitution. For example,
$m = Compute("$10.99");
will most likely set $m to the Real value .99 rather than the monitary value of $10.99, since perl thinks $10 is the name of a variable, and will substitute that into the string before processing it. Since that variable is most likely empty, the result will be the same as $m = Compute(``.99'');
You can use monitary values within computations, as in
$m1 = Compute('$10.00');
$m2 = 3*$m1; $m3 = $m2 + .5;
$m4 = Compute('$10.00 + $2.59');
so that $m2 will be $30.00, $m3 will be $30.50, and $m4 will be $12.59. Students can perform computations within their answers unless you disable the operators and functions as well.
The tolerance for this context is set initially to .005 and the tolType to 'absolute' so that monitary values will have to match to the nearest penny. You can change that on a global basis using
Context()->flags->set(tolerance=>.0001,tolType=>"relative");
for example. You can also change the tolerance on an individual currency value as follows:
$m = Compute('$1,250,000.00')->with(tolerance=>.0001,tolType=>'relative');
By default, the answer checker for Currency values requires
the student to enter the currency symbol, not just a real number.
You can relax that condition by including the promoteReals=>1
option to the cmp() method of the Currency value. For example,
ANS(Compute('$150')->cmp(promoteReals=>1));
would allow the student to enter just 150 rather than $150.
By default, the students may omit the commas, but you can
force them to supply the commas using forceCommas=>1 in
your cmp() call.
ANS(Compute('$10,000.00')->cmp(forceCommas=>1));
By default, students need not enter decimal digits, so could use $100 or $1,000. as valid entries. You can require that the cents be provided using the forceDecimals=>1 flag.
ANS(Compute('$10.95')->cmp(forceDecimals=>1));
By default, if the monitary value includes decimals digits, it must have exactly two. You can weaken this requirement to allow any number of decimals by using noExtraDecimals=>0.
ANS(Compute('$10.23372')->cmp(noExtraDecimals=>0);
If forceDecimals is set to 1 at the same time, then they must have 2 or more decimals, otherwise any number is OK.
By default, currency values are always formatted to display using two decimal places, but you can request that if the decimals would be .00 then they should not be displayed. This is controlled via the trimTrailingZeros context flag:
Context()->flags->set(trimTrailingZeros=>1);
It can also be set on an individual currency value:
$m = Compute('$50')->with(trimtrailingZeros=>1);
so that this $m will print as $50 rather than $50.00.