WeBWorK Problems

Showing Fractions instead of Decimals

Showing Fractions instead of Decimals

by Daniele Arcara -
Number of replies: 3
We are trying to create some simple tangent line questions coming from implicit differentiation. The slope naturally comes out as a fraction from calculating dy/dx using implicit differentiation. We would like the answer to the problem to display the slope as a function instead of as a decimal. Is there any easy way to do that?

Here is a code that works, but gives us a decimal:

DOCUMENT();

loadMacros(
  "PGstandard.pl",
  "PGML.pl",
  "PGcourse.pl",
  "MathObjects.pl",
  "parserImplicitEquation.pl",
);

TEXT(beginproblem());

Context("ImplicitEquation");

$f = Formula("x**2+3*y**3");
$dx = $f -> D('x') -> reduce();
$dy = $f -> D('y') -> reduce();
$slope = -$dx/$dy;
$y = 1;
$x = 1;
$slopeeval = $slope -> eval(x => $x, y => $y);
$ans = ImplicitEquation("y-$y=$slopeeval*(x-$x)");

BEGIN_PGML
Find the line that is tangent to the graph of the equation [`` [$f] = 4 ``] at the point [`` ([$x],[$y]) ``].    
 
[_____________________________]{$ans}.
END_PGML

ENDDOCUMENT();

We tried playing around with the Context("Fraction"), but we were not successful in making it mix fractions and implicit equations together.

Thank you!
In reply to Daniele Arcara

Re: Showing Fractions instead of Decimals

by Andrew Parker -
As you have it coded, $slope is a Formula, and $slopeeval is the result of evaluating $slope at ($x,$y). Calling eval will always result in the final computation, meaning that no operations will be preserved. So $slopeeval being defined in this way will never be a fraction.

You're also going to need to turn off the reduceConstants context flag to avoid turning fractions into decimals:
Context()->flags->set(reduceConstants=>0);

Now, unless you are going to use $dx and $dy in a displayed solution, you don't need to call reduce after taking the derivative. You're more interested here in their value at ($x,$y), so replace the "reduce" call with -> eval(x=>$x, y=>$y).

$f = Formula("x**2+3*y**3");
$y = 1;
$x = 1;
$dx = $f -> D('x') -> eval(x => $x, y => $y);
$dy = $f -> D('y') -> eval(x => $x, y => $y);

This will get you the numerator and denominator of your slope, so you can set:

$ans = ImplicitEquation("y-$y=-($dx/$dy)*(x-$x)");

However, if you're looking to randomize this problem (or change $f), you're going to run into some more problems.

Here's my suggestion for randomizing this problem. It should allow you to code up as many variants as you like by simply changing the definition of $f. 


DOCUMENT();

loadMacros(
  "PGstandard.pl",
  "PGML.pl",
  "PGcourse.pl",
  "MathObjects.pl",
  "parserImplicitEquation.pl",
);

TEXT(beginproblem());

Context("ImplicitEquation");
Context()->flags->set(reduceConstants=>0); # Preserve constant formulas
Context()->variables->set(x=>{limits=>[-5,5]}, y=>{limits=>[-5,5]});

$f = Formula("x**2+3*y**3");
$y = random(-5,5,1);
$x = random(-5,5,1);
$result = $f -> eval(x=>$x, y=>$y); # so that our random point lies on $f = $result
$dx = $f -> D('x') -> eval(x=>$x, y=>$y);
$dy = $f -> D('y') -> eval(x=>$x, y=>$y);


# manually reduce the slope fraction #
##############################
$gcf = gcf(abs($dx),abs($dy));
$dx = Real("$dx/$gcf");
$dy = Real("$dy/$gcf");

if ( ($dx < 0 && $dy < 0) || ($dx > 0 && $dy > 0) ) {
  $m = Formula("-(abs($dx)/abs($dy))");
} else {
  $m = Formula("abs($dx)/abs($dy)");
};

# reduce potential subtraction of negatives in our solution #
###############################################
$lhs = Formula("y-$y")->reduce;
$rhs = Formula("x-$x")->reduce;

# throw in the slope AFTER calling reduce, to preserve the fraction #
######################################################
$rhs = Compute("$m*$rhs");

$ans = ImplicitEquation("$lhs=$rhs"); 

BEGIN_PGML
Find the line that is tangent to the graph of the equation [`` [$f] = [$result] ``] at the point [`` ([$x],[$y]) ``].    

[_____________________________]{$ans}.
END_PGML

ENDDOCUMENT();

In reply to Andrew Parker

Re: Showing Fractions instead of Decimals

by Andrew Parker -
Something that didn't occur to me right away with the randomization, it will be necessary to avoid $dx = 0 or $dy = 0...

$f = Formula("x**2+3*y**3");
$fx = $f -> D('x');
$fy = $f -> D('y');

# repeatedly generate random points until we get non-zero dx and dy #
########################################################
do { 
  $y = random(-5,5,1);
  $x = random(-5,5,1);
  $dx = $fx -> eval(x=>$x, y=>$y);
  $dy = $fy -> eval(x=>$x, y=>$y);
} until ( $dx != 0 && $dy != 0 );

$result = $f -> eval(x=>$x, y=>$y); # so that our random point lies on $f = $result

Just make sure that whatever you choose for $f has non-zero partials.
In reply to Daniele Arcara

Re: Showing Fractions instead of Decimals

by Alex Jordan -
If you use contextFraction.pl, and use Context("Fraction"), then you can make

$slopeeval = Fraction(-$dx-> eval(x => $x, y => $y), $dy-> eval(x => $x, y => $y))

using two arguments to Fraction. It will be a Fraction object with the numerator and denominator reduced. (I'm not sure what happens if the numerator and denominator are not integers, but the sample code given in the post will produce integers.)

You can also make
$slopeeval = Fraction((-$dx-> eval(x => $x, y => $y)) / ($dy-> eval(x => $x, y => $y)))

which carries out the division and passes one (likely decimal) argument to Fraction. The result will be a reduced fraction that is probably equal to what you fed it, as long as the denominator of what you fed it was not too large.

I'd do your $f, $dx, $dy, etc in Numeric context. Then switch to Fraction context to make this $slopeeval. Then go to ImplicitEquation context to write the equation, but remember to set the reduceConstants flag to 0 so that the string fraction is not reduced to a decimal again.