WeBWorK Problems

Can't take acos of 1 or -1?

Can't take acos of 1 or -1?

by Chrissy Safranski -
Number of replies: 5
I wrote a linear algebra inner product problem, similar to the ones in the library, and it worked perfectly, except with seeds where it was trying to take the inverse cosine of 1 or -1, and then the problem wouldn't render at all and gave the error in my subject line. Any ideas why that would be the case? Both those values are in the domain of arccos, obviously.

The relevant part of my code had looked like this:
$norm_u = sqrt($norm_u);
$norm_v = sqrt($norm_v);
$angle = arccos($prod/$norm_u /$norm_v );

Once the problem was brought to my attention, I was able to fix it, by doing this:

if ($prod>0 and $prod*$prod == $norm_u *$norm_v ) {$angle=0;}
elsif ($prod<0 and $prod*$prod == $norm_u * $norm_v ){$angle=pi;}
else {$angle = arccos($prod/sqrt($norm_u) /sqrt($norm_v) ); }

$norm_u = sqrt($norm_u);
$norm_v = sqrt($norm_v);

But my first attempts at a fix also failed to work, like putting the if-clause after I had taken the square roots (the if-clause wouldn't trigger and the same error would occur).

I am running an older version of WebWork (2.10), but this still seems like a weird problem to have.

In reply to Chrissy Safranski

Re: Can't take acos of 1 or -1?

by Alex Jordan -
Computing square roots and doing division is likely to result in machine rounding error. So where you were expecting something to be 1, it might actually be:
1.000....0001
or something like that, and then arccos could fail to accept it as input.

To address this particular situation, you could do something to round the result of $prod/$norm_u /$norm_v to some appropriate number of decimal places before applying arccos.

It would be nice if you could do all of these things with MathObjects, and if the MathObjects version of arccos was actually a function that accepted inputs slightly larger than 1 (by the zeroTolerance) but treated them as 1.
In reply to Alex Jordan

Re: Can't take acos of 1 or -1?

by Chrissy Safranski -
Thank you for your quick reply! Your guess was why I ended up writing the if-clause the way I did - without square roots or division - because when the clause didn't trigger, I figured it had to be machine rounding error. But the error given on the problem said "Can't take acos of 1" or "Can't take acos of -1" which surprised me. If it had said "Can't take acos of 1.001" I would have understood the problem sooner.

I'll have to go back and check how the library problems manage it - I copied and pasted from one of them as my starting point, and I only changed the inner product being used, not the questions asked, so I really didn't expect an issue like this.
In reply to Chrissy Safranski

Re: Can't take acos of 1 or -1?

by Alex Jordan -
Another approach would be to avoid machine rounding error by keeping things integer as long as possible. (I am assuming your vector entries are integers.)

So:
arccos(sqrt((($u . $v)**2)/(($u . $u)*($v . $v)))

In the situation where the issue arises, I would expect both ($u . $v)**2 and ($u . $u)*($v . $v) to be the same integer. And then the division will work out to exactly 1, and the sqrt will work out to exactly 1, and arccos will be happy.

I haven't tried it though.
In reply to Alex Jordan

Re: Can't take acos of 1 or -1?

by Chrissy Safranski -
Thank you for that other idea! The vector entries are indeed integers. I was using an alternate inner product, not simply the dot product, but I could modify your specific code to get what I want.

But wait, wouldn't that lose the situation where $u.$v is the negative of the product of the lengths?


In reply to Alex Jordan

Re: Can't take acos of 1 or -1?

by Alex Jordan -
My post came back to me and I realized it doesn't allow for negative arguments to arccos. Does Perl have a signum function? The wiki says you can use sgn()
(http://webwork.maa.org/wiki/Available_Functions)

So then:
arccos(sgn($u . $v) * sqrt((($u . $v)**2)/(($u . $u)*($v . $v)))