WeBWorK Problems

fuzzy comparisons in use even when I don't want them

fuzzy comparisons in use even when I don't want them

by Alex Jordan -
Number of replies: 4

I have a custom answer checker that's part of a custom context I am working on. Part of this contest is trying to disallow decimal answers only when they happen to be exactly correct. So for example if the real answer is something like Formula("1/2") then I would have it accept "0.5". If the answer is Formula("1/3") then ideally there should be no acceptable decimal answer that could be typed. But I don't want to simply mark "0.33" as wrong. I want to pass an error message that decimal approximations are not accepted. Again, if they enter 0.5 for 1/2, in that case I just want to let it through.

There's a lot more going on in this context, but this is the aspect where I am hitting a puzzle.

In the answer checker, I look in the answer hash to see $ans->{student_formula}, and assess if they even entered a decimal answer in the first place. (I'm using the patter match /\s*[\+\-]?\d*\.\d+\s*/.) If they entered a decimal number, I move into doing this special decimal checking outlined above. If not, I skip this and do other things with their answer.

I expected that I could get the perl real version of their answer, and the perl real version of the correct answer, do a comparison, and it would not use MathObject fuzzy comparison. So for example, I would condition like:

if ($student->value == $correct->eval()->value)
  {award credit} #because their decimal answer is an exact match with the correct answer
else
  {return a message that decimal approximations are not OK}
  #because they entered a decimal and it was not an exact match

But that conditional ($student->value == $correct->eval()->value) is working out to be true under fuzzy real equivalence conditions. For example, with a correct answer of Formula("3/8") (with reduceConstants=>0) and a student answer of 0.3751, it results in true.

So it seems the == operator is promoting the operands to Real() and using fuzzy comparisons. Or something else that I don't understand.

My root question: how should I do an exact value comparison between two Real()s without changing the context tolType and tolerance?


In reply to Alex Jordan

Re: fuzzy comparisons in use even when I don't want them

by Alex Jordan -

It seems I misunderstood my issue (which is not surprising). I will try to boil it down differently.

If a student enters an answer:
0.3750001

Is there anywhere in the answer hash that still keeps that number down to all its precision? When I print the answer hash, I see:

original_student_ans => 0.375

And if I test a comparison:
($ans->{original_student_ans} == 0.3750001)
the result is false. So even $ans->{original_student_ans} is not really what the student typed.

I'm thinking it is probably relevant that this answer is checked as part of a list. So the individual checker is being passed something from the list checker, but it's not a completely faithful representation of what the student typed.


In reply to Alex Jordan

Re: fuzzy comparisons in use even when I don't want them

by Glenn Rice -

The original_student_ans is set directly from the html input, stored as a string, and usually the only thing that is done to the original_student_ans is that whitespace is trimmed from the beginning and end.  So "usually" if the student enters 0.3750001 then that is what the original_student_ans will be.  This is consistent with my testing of this in problems.  When I show the answer hash info, that is what I see.

Now, I say "usually" because there are other things that can happen that might modify the original_student_ans.  Some macros do this.  So you might check the macros that you are loading, and see if any of them do this.

In reply to Alex Jordan

Re: fuzzy comparisons in use even when I don't want them

by Davide Cervone -

I'm also not able to reproduce this. The original_student_ans is .3750001 for me, and the equality check returns true. The fuzzy quality should only be triggered if one (or both) of the operands are MathObjects. Note that whether the return value of ->value is a MathObject or not depends on the type of MathObject whose value is being taken. For a Real MathObject, it should be a perl real, but for a Point or Vector, it would be an array of Real MathObjects.

I don't think any of the MathObject answer checkers modify the original_student_ans, so I believe you should be able to rely on that.

I you are able to post code, we could look more closely to see what might be happening.

In reply to Alex Jordan

Re: fuzzy comparisons in use even when I don't want them

by Alex Jordan -

Thank you Davide, Glenn, for looking into it. I'm sorry for the noise. I was wrong to attribute some behavior to fuzzy checking. There was a place in my list checker that was using the string method on an individual answer, and this trickled down to where I was stumped. The string method was of course turning something like 0.3750001 into 0.375, so the individual checker did not see the 0.3750001. At least I understand now the root cause of my issue.

Later today I will keep working on the project and see if I can get my list checker to pass an unparsed component from a student list answer to my individual checker. Either that, or I can now imagine alternatives to what I am trying to do.