WeBWorK Problems

Numerical compute difficulty

Numerical compute difficulty

by Murray Eisenberg -
Number of replies: 5
In the following .pg file, why does WeBWorK incorrect calculate the value of $ratio to be 0.0666667 instead of 0.00001 and hence count the correct answer as wrong?
DOCUMENT();
loadMacros(
 "PG.pl",
 "PGbasicmacros.pl",
 "MathObjects.pl",
);

Context("Numeric");

# INITIALIZATION
$order = 5;
$multiplier = 10;
$ratio = Compute(1/($multiplier^$order));


TEXT(beginproblem());
Context()->texStrings;
BEGIN_TEXT

The method has error \(O(h^$order)\).
You run the method once with \(n\) steps and then
a second time with $multiplier times as many steps.
You should expect the error the second time to be
roughly what fraction of the error the first time?
$BR \{ans_rule(8)\}

END_TEXT
Context()->normalStrings;

# ANSWERS
ANS($ratio ->cmp() );

Context()->texStrings;
SOLUTION(EV3(<<'END_SOLUTION'));
$PAR SOLUTIONS $PAR
$PAR

The ratio of the new error to the original error is roughly
\[
\frac{(h/$multiplier)^$order}{h^$order}= \frac{1}{$multiplier^$order} = $ratio.
\]

Testing:
$BR
\(\text{multiplier} = $multiplier,\)$BR
\(\text{order} = $order,\)$BR
\( \text{ratio} = 1/($multiplier^$order), \)$BR
\( \text{computed ratio} = $ratio . \)

END_SOLUTION
Context()->normalStrings;

ENDDOCUMENT();
In reply to Murray Eisenberg

Re: Numerical compute difficulty

by Michael Gage -
The short answer is you need quotes in the compute statement:

Compute("1/($multiplier^$order"));

since the input to Compute() should always be a string.

To see what exactly is going wrong I used the PGlabs calculator
at http://webwork.maa.org/wiki/PGLabs
 $ans = 1/10000;
TEXT(Compute($ans), $PAR);
TEXT($ans);
yields
0.0001
0.0001
but
 $ans = 1/1000000;
TEXT(Compute($ans), $PAR);
TEXT($ans);
yields
-3.28172
1e-06

The upper number is e-6. If perl wrote 10^(-6) as
1E-06 instead of 1e-06 you would have been ok, but
I haven't figured out how to force WeBWorK to do that.

In any case it is best to use a string input to Compute() so that
you can control the exact form of the correct answer which is shown to students once they are allowed to see the correct answer.
In reply to Michael Gage

Re: Numerical compute difficulty

by Murray Eisenberg -
Hmm...Then I don't understand something and obviously need a longer answer! The code I showed was an excerpt from a longer question. In the initialization section of that same question I included the following:
$ordLocal = random(2,6,1);
$ordLocalMinus = Compute($ordLocal - 1);
$globalOrdAns = Formula("h^$ordLocalMinus");
I did not use quotes in the Compute command shown above, but still the value of $globalOrdAns was correctly computed. Did the Compute in the line assigning $ordLocalMinus just get ignored but the value of $ordLocalMinus actually get calculated (so it could correctly be fed to the Formula command?

If so, when are the quotes required and when not?
In reply to Murray Eisenberg

Re: Numerical compute difficulty

by Davide Cervone -
The problem is that ^ is not exponentiation in perl, it is exclusive or. You need to use ** in perl expresions. Both ** and ^ work within the MathObject expressions, but not in perl expressions, which is why Mike's suggestion of putting the formula in quotes works.

If you use ^ with a MathObject, it will warn you about this, but since you were using perl reals, not MathObjects, it went ahead and did the exclusive or. Silly, but true.

Davide
In reply to Davide Cervone

Re: Numerical compute difficulty

by Murray Eisenberg -
So I still don't understand when I should use quotes and when not around the argument to Compute. As a "rule", should I just always use them?
In reply to Murray Eisenberg

Re: Numerical compute difficulty

by Davide Cervone -
It depends on what result you want. Without quotes, perl will do the computations before passing the result to Compute(), which will then turn the result into a MathObject Real (unless the perl computation already involves MathObjects and results in some other MathObject type). It is perfectly fine to do that, and it is somewhat more efficient since it does not involve the expensive step of parsing the expression by the MathObject parser. For a Real value, that is probably a reasonable thing to do, as long as you remember things like the difference (in perl) between ^ and **.

When you pass a string to Compute(), it will first parse it using the MathObject parser, as controlled by the current Context object. That means that the operations and functions and so on that are defined there will be the ones that control the result, no the built-in perl expression parser. That makes the result work exactly like student answers, which is good for consistency, and also makes it easier to produce results that are not easy to produce in perl (like Intervals, and Vectors). Finally, Compute() saves the original string as the correct answer string, so that if you used

    $ans = Compute("sqrt(2)");
to produce a MathObject that was used for an answer checker via
    ANS($ans->cmp);
then the correct answer would show as sqrt(2) rather than 1.41421 as it would have been had you used Compute(sqrt(2)) without the quotes.

I don't think there is a hard-and-fast rule for when to use quotes and when not to. You have to think about what result you want to have in terms of the correct answer as well as the computed result.

Hope that clears things up for you.

Davide