WeBWorK Problems

Is it easy to require answers in base-exponent form

Re: Is it easy to require answers in base-exponent form

by Davide Cervone -
Number of replies: 0
It's not exactly easy to check that a value is expressed as an exponentiation, but it can be done using a custom checker. Here's an example:
    ANS(Compute("2^3")->cmp(checker => sub {
      my ($correct,$student,$ans) = @_;
      return 0 unless $correct == $student;
      my $tree = $student->{equation}{tree};
      if ($tree->class eq 'BOP' && ($tree->{bop} eq '^' || $tree->{bop} eq '**') &&
          $tree->{lop}->class eq 'Number' && $tree->{rop}->class eq 'Number') {
        return 1 if $tree->{rop}{value} != 1;
        Value->Error("Your exponent should not be 1") unless $ans->{isPreview};
        return 0;
      }
      Value->Error("Your answer should be in the form of a power: a^b")
        unless $ans->{isPreview};
      return 0;
    }));
Here, we check first that the answer is correct, and if it is, we check that it is of the desired form. This looks at the parsed equation that was used to generate the student's numeric answer, and see whether that is an exponentiation of two numbers.

There are a couple of problems with this. First, it doesn't allow things like 2^-3 or (-2)^3, since the negatives are handled as unary operations (not sure you want to allow that anyway). Second, it doesn't require that the operands be integers.

You can solve the last one by using Parser::Number::NoDecimals after setting the context you plan to use. If you want to allow negative operands, then you need to do a little more checking for the left- and right-hand operands:

    ANS(Compute("2^3")->cmp(checker => sub {
      my ($correct,$student,$ans) = @_;
      return 0 unless $correct == $student;
      my $tree = $student->{equation}{tree};
      if ($tree->class eq 'BOP' && ($tree->{bop} eq '^' || $tree->{bop} eq '**') &&
          isNumber($tree->{lop}) && isNumber($tree->{rop})) {
        return 1 if $tree->{rop}{value} != 1;
        Value->Error("Your exponent should not be 1") unless $ans->{isPreview};
        return 0;
      }
      Value->Error("Your answer should be in the form of a power: a^b")
        unless $ans->{isPreview};
      return 0;
    }));

    sub isNumber {
      my $op = shift;
      return $op->class eq 'Number' ||
         ($op->class eq 'UOP' && $op->{uop} eq 'u-' && $op->{op}->class eq 'Number');
    }
Here we define a helper function that checks if an operand is a number or a unary minus applied to a number.

As for the decomposition into powers of primes, that would be more complicated, and probably deserves a separate context that would produce the errors as the equation is being parsed rather than retroactively going over the equation after the fact.

Davide