The contextScientificNotation.pl
macro file might be a better choice, as it already implements optional minimum (and maximum) required precision values.
I also remember having written a FixedPrecision
class for Ken Appel. I looked it up and have attached the fixedPrecision.pl
file, but also list it here.
sub _fixedPrecision_init {}
package FixedPrecision;
our @ISA = ("Value::Real");
sub new {
my $self = shift; my $class = ref($self) || $self;
my $context = (Value::isContext($_[0]) ? shift : $self->context);
my $x = shift; my $n = shift;
Value::Error("Too many arguments") if scalar(@_) > 0;
if (defined($n)) {
$x = main::prfmt($x,"%.${n}f");
} else {
$x =~ s/\s+//g;
my ($int,$dec) = split(/\./,$x);
$n = length($dec);
}
$self = bless $self->SUPER::new($context,$x), $class;
$self->{decimals} = $n; $self->{isValue} = 1;
return $self;
}
sub string {
my $self = shift;
main::prfmt($self->value,"%.".$self->{decimals}."f");
}
sub compare {
my ($self,$l,$r) = Value::checkOpOrder(@_);
$l cmp $r;
}
package FixedPrecisionNumber;
our @ISA = ("Parser::Number");
sub new {
my $self = shift; my $class = ref($self) || $self;
my $equation = shift; my $context = $equation->{context};
$self = bless $self->SUPER::new($equation,@_), $class;
$self->{value} = FixedPrecision->new($self->{value_string});
return $self;
}
sub string {(shift)->{value}->string(@_)}
sub TeX {(shift)->{value}->TeX(@_)}
package main;
Context()->{parser}{Number} = "FixedPrecisionNumber";
sub FixedPrecision {FixedPrecision->new(@_)};
1;
This file defines a new MathObject class (FixedPrecision
) that is a subclass of the Real
class and adds a new field {decimals}
that determines how many decimal places to use. It also creates a Parser
class that replaces the standard Number
class that uses the new FixedPrecision
object to implement numbers in the Parser
.
By default, FixedPrecsion(x)
will take however many decimal digits there are in 'x' as the number of digits, or you can specify the number explicitly as FixedPrecision(x,digits)
. For example, FixedPrecision(sqrt(2),3)
would produce a value 1.414
that the student must match exactly.
You should use this within the LimitedNumeric
context, as in the following example:
DOCUMENT();
loadMacros(
"PGstandard.pl",
"Parser.pl",
);
TEXT(beginproblem());
Context("LimitedNumeric");
loadMacros("fixedPrecision.pl"); # must come after Context is set.
$n = FixedPrecision(sqrt(2),3);
BEGIN_TEXT
\($n\) = \{ans_rule(10)\}
END_TEXT
ANS($n->cmp);
ENDDOCUMENT();
The FixedPrecision
class overrides the string
and compare
methods to implement the fixed-precision output and to do a string comparison rather than a (fuzzy) numeric comparison, so that only the exact number of digits will be marked correct.
Note that this is not a full implementation of a MathObject class, which would have to be more sophisticated in order to handle things like addition, subtraction, and so on correctly. This means it can only be used in the LimitedNumeric
context where those operations will never be performed. This class also won't handle scientific notation properly. It would be possible to make a more complete implementation of this idea, but there are details to be worked out.
Davide