Using the multianswer parser I can access only the last "original_student_ans"
The pared-down code is below. hp
DOCUMENT();
loadMacros(
"PGbasicmacros.pl",
"MathObjects.pl",
"PGanswermacros.pl",
"parserMultiAnswer.pl",
);
#######################
TEXT($BEGIN_ONE_COLUMN,beginproblem()) ;
$refreshCachedImages = 1;
$showPartialCorrectAnswers = 1;
###############
$H = 0.43;
$W = 5.57;
$A = $H*$W;
$P = 2*$H + 2*$W;
$multians = MultiAnswer($H, $W, $A, $P)->with(
singleResult => 0,
checker => sub {
my ( $correct, $student, $self, $answer_hash_reference ) = @_;
my %ansH = %$answer_hash_reference;
@keys = keys %ansH;
foreach(0..@keys){
$strkeys = $strkeys.$keys[$_]." ";
}
my ($H_stu, $W_stu, $A_stu, $P_stu ) = @{$student};
# my ($H_oa, $W_oa, $A_oa, $P_oa )= @{$ansH} {original_student_ans};# unsuccessful
$H_n = Nsigfig($ansH{original_student_ans}); #last entry only one available
my ( $H_correct, $W_correct, $A_correct, $P_correct) = @{$correct};
$A_correct = $H_stu*$W_stu;
$P_correct = 2*$H_stu+2*$W_stu;
$self->setMessage(1,"number sigfigs for last only $H_n ");
$self->setMessage(2, $strkeys );
$self->setMessage(3,$W_oa);
$self->setMessage(4,$ansH{original_student_ans});
if($H_n ==3){
return [1,1,1,1]}
else {
return [0,0,0,0];
}
}
);
BEGIN_TEXT
Record the horizontal dimension. \{$multians->ans_rule(10)\} $BR
Record the vertical dimension. \{$multians->ans_rule(10)\} $BR
Calculate the area. \{$multians->ans_rule(10)\} $BR
Calculate the perimeter. \{$multians->ans_rule(10)\} $BR
END_TEXT
ANS($multians->cmp() );
sub Nsigfig{
($x) = @_;
$_=$x;
if (m/./){
$xPlus = $x."1";
$n =int ( ln($xPlus/($xPlus-$x))/ln(10) );}
else {#tba
}
return $n;
}
TEXT($END_ONE_COLUMN);
ENDDOCUMENT();
Note that the
original_student_ans
property lists the unprocessed student answer, so I'm not sure what your use is for that rather than the MathObject that results from parsing that answer.
1.1 has two significant digits
1.10 has three significant digits
The trailing zero gets "lost" in the "student answer" and what the student has entered is unknown.
hp
You can get the original string from the student answer as follows. If
$s
is a value from the @student
array, then $s->{equation}{string}
is the original string for the student's answer.So in your case,
$A_stu->{equation}{string}
would be what you are looking for.Note that the correct answers may or may not have an
equation
property, depending on how they were created. If you used $H = Compute(0.43)
then it would. For values with trailing zeros, you would need to use $H = Compute("1.20")
to be able to detect the trailing 0 in the string, since Compute(1.20)
first converts the number to a Perl real, and then that is turned into a string, and finally that is parsed by MathObjects, so the trailing 0 is lost before Compute()
is even called.Note, however, that your problem doesn't prevent a student from entering and expression rather than a single number, so the equation string could be something like
1.2 + .03
. Perhaps you want to use Context("LimitedNumeric")
to prevent that.To really do such problems correctly, you would need a new context in which significant figures are tracked through the operations performed (though it is not clear to me what the number of significant figures should be for something like
sin(1.23)
). That could be done, but it would be a substantial bit of work to create it.
sin(1.57)
Wikipedia refers to the rules of significant figures as "approximate" rules. This means that anything goes and that you make it up as you go along.
The 1.57 is the measured value; measured properly the last (the 7) is the only one having the distinction of being estimated. The actual value could easily be any of 1.55,1.56,1.67, 1.68 etc (to a point).
I choose to try a couple and examine the output on the calculator.
sin(1.57) = 0.9999996829
sin(1.56) = 0.9999417202
The "wiggle" seems to be trensferred from the 2nd digit past the decimal to the 5th one past the decimal.
sin(1.57) = 1.00000 (now we have 6 significant digits which includes one uncertain one)
My first year university in the physics lab: measurements were 99, 98,101 !!!
I said: the 101 has 3 sigfigs and the 98 has 2. How can one of these numbers, in a certain sense, be considered 10 times better than its neighbours? The professor told me that I should think about things a bit and that if there was an error of serveral percent in one number it should carry through in calculations. I was to use my judgement and,at that tender age, it was left in my lap.
Some years later I discussed the above example with a colleague. Where he worked they had a special rule to deal with the situation of the leading 1; I cannot remember what it was. As I write the measurement question I am trying to avoid these numbers.
Students need to put some thought into it and not automatically copy ten digits of the calculator. It's about the presentation. Maybe they sould also write 0.5 intead of .5 . I am imagining that the issue may easily be in a communications course: nouns, verbs, double negatives, deceptive graphs and significant figures.
The subject does not seem to be a good fit for a computer.
Maybe this is part of a grander philosophical discussion as to whether we want a society where everybody followes rules as opposed to a society where everybody makes it up as they go along.
Thanks again
hp
Certainly that is what most students do (and people in general as well).
Of course, I'm sure you know that there are specific rules for how to handle significant digits in addition/subtraction and in multiplication/division; the problem comes with what to do with function application.
If the function is something like a polynomial, or a quotient of polynomials, then it is no problem, because you can use the rules for addition and multiplication to track the significant digits through the computation.
But for something like sin(x) or sqrt(x) or exp(x), or 2^x, it is not immediately clear what should be done. One approach would be to express the function as a truncated Taylor series, and apply the addition and multiplication rules to the resulting polynomial.
Of course, to do this properly on a computer or calculator, one would need to know which Taylor polynomial was used (how many terms, and the center about which the expansion was taken), but we don't generally have that. (In fact, nowadays computers don't use such series as they once did, but instead have large tables of precomputed values with interpolation between those values -- like the old days of log tables. Funny how things come back around to their roots.)
Since the Taylor series will involve multiplication, the precision of the result will not be allowed to exceed the precision of the argument, according to the rule for multiplication, so it might be reasonable to use that as a fallback.
Your analysis of sin(1.57) is more about the way sin(x) works in the neighborhood of x=1.57 than about how to handle significant figures. For example, since the derivative of sin(x) is cos(x), one can estimate the change in sin(x) at x=1.57 for a change of h in x by using h*cos(1.57) (the slope of the tangent line at x=1.57 times the change in x). Since cos(1.57) is about .00079632, and your x is changing by .01, that means sin(x) should change by about .000007, so you should see changes in the 6th digit, and probably the 5th (as you get carries). This corresponds to your seeing changes in the 5th digit.
But this doesn't say that your origin value of sin(1.57) has 6 significant digits. (It may be that the computations leading to that value of sin(x) don't have that precision. Of course, they do in this case, but that doesn't follow from the analysis, though it does give you a sense of what is reliable.)
In terms of your 99, 98, 101 measurements, I understand the sense in which you mean that one is 10 times more accurate than the others, but (as I'm sure you know), it is false sense. If the "correct" value were actually 100, then 99 and 101 are both equally precise, as they both have an (absolute) error of 1, so their relative error is 1%, meaning they each have 2 reasonably accurate digits.
The subject does not seem to be a good fit for a computer.
Actually, it is a crucial idea when you are using computers, as it affects every computation (with real numbers) that you make. It turns out that it comes up a lot in WeBWorK problems, and an understanding of its consequences is important when you write WeBWorK problems.
Here's one example of the kind of thing I mean. We all know that the derivative of f(x) is the limit as h goes to 0 of (f(x+h)-f(x))/h, so we can approximate the derivative f'(x) by (f(x+h)-f(x))/h for a small value of h. The smaller h is, the better the approximation, right?
Well, here is a table of results for f(x) = e^x for h = 1/10^i for i from 1 to 13 with x = 0. The value given is the error from the correct value (of f'(0) = 1 in this case).
1: 0.049959657927277 2: 0.004999970020186 3: 0.000499999932507 4: 0.000049999985868 5: 0.000004999995467 6: 0.000000499972891 7: 0.000000050332566 8: 0.000000008144091 9: 0.000000036264830 10: 0.000000296802077 11: 0.000003033866997 12: 0.000019170593496 13: 0.000313896313892
Note that the error goes down from 1 to 8, but then starts to go up again. So h = 1/10^8 gives the most accurate value, even though we can easily represent smaller h's. This seems counter-intuitive. I will let you think about this rather than give it away, but this an example of the main cause of error in computer calculations (other than programmer error). An understanding of it will go a long way helping one avoid such issues when writing WeBWorK problems.
hp
The fact that there isn't a good way of coding for sig figs is a problem.
Davide, your suggested solution for controlling the number of decimal places instead (fixedPrecision.pl, thank you!) needs to be carefully coupled with the use of appropriate parameter values in the problem itself. Matching to $int.$dec patterns as strings, one needs to be sure to avoid crossing digit-count boundaries, like 99 to 100. For example, imagine verifying C=2*pi*r and A=pi*r^2.
...
Context("LimitedNumeric");
loadMacros("fixedPrecision.pl"); # must come after Context is set.
TEXT(beginproblem());
$r=FixedPrecision(random(5.65,9.90,0.01),2); # this ensures 3 sig figs of r
$C=FixedPrecision(2*pi*$r,1); # r_max <= min(9.9,100/(2*pi)) to ensure 2 digits before decimal in circumference, for 3 sig figs
$A=FixedPrecision(pi*$r*$r,0); # r_min >= sqrt(100/pi)=5.64 to ensure 3 digits before decimal in area, for 3 sig figs
BEGIN_TEXT
A circle has radius \($r\) m.
$PAR
(a) The circumference of the circle is: \{ ans_rule(20) \} m
$PAR
END_TEXT
ANS($C->cmp);
BEGIN_TEXT
(b) The area of the circle is: \{ ans_rule(20) \} m<sup>2</sup>
END_TEXT
ANS($A->cmp);
...
Unfortunately, it does not resolve the issue of using scientific notation on entry. Perhaps, there is a way to pre-process those? - I am a webwork newbie, so do not know yet.
Perhaps a better tack would be to verify the numerical closeness as well as the sig fig count, and to set the numerical tolerance value to be 1/2 of 1 in the last sig fig. A challenge perhaps some perl/webwork expert can pick up?
I only want to add here that I had to modify slightly Davide's fixedPrecision.pl, as it was throwing perl warnings for "uninitialized value of $dec" for all whole numbers, so the core part is changed like this:
$x =~ s/\s+//g; my ($int,$dec) = split(/\./,$x); if (!defined($dec)) { $n = 0; } else { $n = length($dec); }
The uninitialized $int (like in entering .123 instead of 0.123) does not seem to present any problem, as it is used only as an output string, not in any function call. I attach a modified version of fixedPrecision.pl.
95 and 105
If we were to just count: one would have two digits the other three.
The 95 would almost have three digits and the 105 would be just a smudge better than having two.
The 105 would be an order of magnitude more precise than the 95!?
Perhaps some information has been lost here and we need to revisit the measurement.
Maybe we can say 95+-1 and 105+-1 (somewhere between 94 and 96 and somewhere between 104 and 106)
or perhaps the best we can say 95+-3 and 105+-3
Perhaps our comfort level should determine whether we should use two digits or three digits at the end.
This conversation with me started as an example of one of the neat things that can be done with a Sketch macro.
I am attaching the problem; you will also need Sketch.pl which I will attach subsequently.
You need to put Sketch.pl in your macros directory.
Note that I have not actually used this problem so I don't know if it works that well.
Hedley
not working well at all; what happened there.
sorry - will work on it.
Hedley
hedley
What we need is a custom answer checker, or an additional method overlaid on the main one.
Something along the lines of this method.