WeBWorK Main Forum

Display reduced fraction in problem and as correct answer

Display reduced fraction in problem and as correct answer

by David Winslow -
Number of replies: 11
How does one display an algorithmically generated fraction, $frac=Formula("$a/$b") in reduced form ($a, $b relatively prime) in a problem and also as the correct answer? I have tried ->reduce but that takes the fraction to a decimal or decimal approximation.
In reply to David Winslow

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
There is no "fraction" MathObject type at the moment (it is one of the "to do" items), so you are going to need to fall back on other WeBWorK tools for that. Fortunately, PGauxiliaryFunctions.pl already includes what you need.
   loadMcaros("PGauxiliaryFunctions.pl");

   $a = random(1,60,1);
   $b = random(1,60,1);

   ($p,$q) = reduce($a,$b);

   BEGIN_TEXT
   \($p/$q\) = \{ans_rule(10)\}
   END_TEXT

   ANS(Compute("$p/$q")->cmp);
should show the correct answer as a fraction in lowest terms. Note that this doesn't force the student to enter it that way. The student could still enter an unreduced fraction, or a decimal version, or a decimal that is "close enough".

Just for future reference, something like $frac = Formula("$a/$b") is a bad idea for several reasons. First, the error messages the student gets will say that it is looking for a formula (rather than a number), which can be misleading. Second, the fraction will be turned into a decimal immediately (Formula usually reduces constant expressions, so that you can do things like Formula("$n x^($n-1)") and have it become 3x^2 when $n=3 rather than 3x^(3-1). This behavior can be turned off by

   Context()->flags->set(reduceConstants => 0);
There is also a flag for reduceConstantFunctions that could be set to 0 to prevent reducing things like sqrt(2) if you wanted those to be visible in the answer.

Finally, the Compute() function used above both produces an appropriate MathObject for the result, but also sets it up so that the correct answer is the original formula used to compute it, not the final reduced answer. So even though the result of Compute("$p/$q") is a decimal real, the answer string will still be "$p/$q".

Hope that does what you want.

Davide

In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by David Winslow -

Davide,

That works great with the added line

if($q==1){$ans=$p;} else {$ans=$p/$q;}

in the event gcd($p,$q)=$q to get $ans which will be the correct answer to display better.

Could you explain your remark about the error message further if Formula("$p/$q") is used when a numerical response is expected? What exactly would the student have to enter to even get an error message? The problem which I am modifying only slightly acutally does have

Context()->flags->set(reduceConstants => 0);

but even if I set it to 1, any constant I enter, correct or incorrect, seems to generate no error messages no matter how compicated the entry is.

Thanks,

David

In reply to David Winslow

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
You give the code snippet
    if ($q==1) {$ans=$p;} else {$ans=$p/$q;}
but I'm a little confused by this, because $ans would then be a decimal representation rather than a fraction, and in the case when $q is equal to one, $ans = $p/$q and $ans = $p both produce identical results (the same Perl real value). Do you mean
  if ($q == 1) {$ans = Real($p)} else {$ans = Compute("$p/$q")}
or something like that? This makes a MathObject for the answer, and in the one case it is just the integer $p, and the other the decimal equivalent of $p/$q, but set up to show as a fraction when the correct answer is displayed. Both will be MathObjects of class Real, and Compute() is simply used only to get the correct answer to show as a fraction rather than the decimal. It would be possible to use Compute("$p") for the first as well, but that is unnecessarily redundant.

In terms of the error messages, the answer checkers can give a message when the student enters something that is not the correct type of answer. For example, this happens when the student types a scalar when a vector is expected, and so on. The result of Formula() is considered to be a function of whatever variables are used in it. If it doesn't contain any variables, that is still a function, but just a constant-valued function.

A decimal or fraction is considered to be of type "Number", while a Formula() that evaluates to a number would be of type "Formula returning a Number". (Formulas could also return vectors, or points, or complex numbers, etc.) Error messages generated by the student entering an incorrect type of answer would say the problem was looking for a "Formula returning a Number" rather than just a "Number" if you were to use Formula() incorrectly this way. For example, if the student entered a list of numbers, e.g., 2,3 as the answer, this would produce a message like "Your answer doesn't look like a Formula returning a Number (it looks like a List of Numbers)" or something to that effect. This would mislead the student into thinking that they should enter a formula involving x's or t's or something. You would rather see the message "Your answer doesn't look like a Number (it looks like a List of Numbers)", which is what you would get from Real($a/$b) rather than Formula("$a/$b").

Worse yet, if the student entered something like 3x, they would get no error message at all, just an indication that the answer is incorrect. That is because WeBWorK thinks the answer is supposed to be a formula, so doesn't complain when the student enters one. If you used a Real instead, the student would get the message "Your answer doesn't look like a Number (it looks like a Formula that returns a Number)", and that could help him or her to identify the problem.

It is usually best to use the correct type of object for the answer you are using rather than something else that just looks the same when printed. There are definitely situations where it can make a difference, and they are not always obvious.

Davide

In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by David Winslow -

Yes, you are correct. The else should have been followed by something like {$ans="$p/$q"}, or if I followed how $ans was given originally in the problem that I am modeling with no redution of the fraction,  I guess I would have used

...else {$ans=Formula("$p/$q")}. Then ANS(Compute("$ans")->cmp) would be used to check the answer.

I now understand your objection to using this. When I was entering possible answers, I never left the realm of constants and therefore no errors were being generated of the type you describe. I guess a reason that the Formula object was used in the original problem  is how its output is given and can be displayed. This problem has a solution which is displayed when answers are available and the variable $ans is used in the solution. If $ans=Formula("$p/$q") is used, \($ans\) goes to \(\frac{$p}{$q}\) and has a slighlty better display. If I use $ans="$p/$q", then \($ans\) is still okay for display.

David

In reply to David Winslow

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
OK, I understand why the problem used Formula() now. When you use $ans=Formula("$p/$q"), then you are correct that ANS(Compute("$ans")->cmp) will now give the correct messages, and that is a reasonable solution, especially if you need to use $ans to produce TeX output, as you do later.

The real solution will be to implement an actual Fraction MathObject class.

Davide
In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
Well, at long last, I have finally implemented a true Fraction object for MathObjects. It is in pg/macros/contextFraction.pl which you can get from the CVS repository. The documentation is in the comments at the top of the file.

Hope this makes things easier for you in the future.

Davide
In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by Patti Lamm -
Davide,
I am a bit confused as to how contextFraction works. I have the following:


Context("Numeric");
Context()->flags->set(reduceConstants => 0);

$b=3'
$ans_d = Compute("$b pi/4");

...

Context("Fraction-NoDecimals");
Context()->flags->set(formatStudentAnswer=>'parsed');

ANS(Compute($ans_d)->cmp);

This correctly forces the student to type 3 pi/4 or 3*pi/4 and gives the correct error if the student types 3 pi/12 or 3*pi/12 or 2.35619.

However, the correct answer (not the student answer) that appears is: 2.35619. How do I get the correct answer to appear as 3*pi/4 ?

Thanks.

In reply to Patti Lamm

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
You should use
    ANS($ans_d->cmp);
rather than
    ANS(Compute($ans_d)->cmp);
Since $ans_d is already a MathObject (it is the result of a Compute() call), so there is no need to use Compute() again.

One of the side-effects of the Compute() function is to set the correct answer string to be exactly what you entered, so it would be "3 pi/4" for $ans_d. After the second ComputeIO, however, the correct answer will be set to (the string version of) the value you entered, and in this case, the string version of the real number is 2.35619, and so that is what is set as the correct answer.

Leaving out the second Compute() should do the trick.

Davide

PS, you don't really need to use the Fraction contexts for this. All you are after is not allowing the student to answer decimal numbers, which can be achieved by

    Context("Numeric");
    Parser::Number::NoDecimals();
This affects whatever context is currently in place.
In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by Patti Lamm -
Thanks for the reply, and especially for the explanations which finally turned some lightbulbs on for this newbie!
In reply to Davide Cervone

Re: Display reduced fraction in problem and as correct answer

by Patti Lamm -
P.S. There's a typo in the macro file contextFraction.pl. In one place it's

Context("Fraction-NoDecimal")

and in another

Context("Fraction-NoDecimals")
In reply to Patti Lamm

Re: Display reduced fraction in problem and as correct answer

by Davide Cervone -
Thanks, I've fixed the comments in the file. Sorry for the confusion.

Davide