Subject: | Wrong (Math::Complex) results in great_circle family of functions |
Date: | Mon, 14 Jan 2008 13:11:17 +0100 (CET) |
To: | bug-Math-Complex [...] rt.cpan.org |
From: | sveshnik [...] fzu.cz |
Hello,
Problem:
great_circle family of functions may produce wrong results on certain input.
Affected versions:
Math::Trig 1.44 and earlier.
Test:
$ perl -MMath::Trig=great_circle_distance -le 'print ref
great_circle_distance(0,0.0002,0,0.0002)'
Expected output:
Empty string (since the result should be just a real number, zero).
Output:
Math::Complex
Description:
This bug is due to the fact, that cos(x)**2+sin(x)**2 is not always 1 in
floating point calculations. For example, cos(0.0002)**2+sin(0.0002) is
greater than 1 by approximately 2.22e-16 on x86 processors. In
great_circle_distance function the following expression is used:
acos(cos( $lat0 ) * cos( $lat1 ) * cos( $theta0 - $theta1 ) +
sin( $lat0 ) * sin( $lat1 ) )
When $theta0 == $theta1 and $lat0 == $lat1 the expression is simplified to
acos(cos($lat0)**2 + sin($lat0)**2)
and for the certain $lat0 it gives numbers larger than 1. After that acos
function returns a Math::Complex result.
Suggested correction:
- return $rho *
- acos(cos( $lat0 ) * cos( $lat1 ) * cos( $theta0 - $theta1 ) +
- sin( $lat0 ) * sin( $lat1 ) );
+ $arg = cos( $lat0 ) * cos( $lat1 ) * cos( $theta0 - $theta1 ) +
+ sin( $lat0 ) * sin( $lat1 );
+ return 0 if $arg > 1;
+ return $rho*atan2(1,1)*4 if $arg < -1;
+ return $rho*acos($arg);
There is a similar problem with acos/asin usage in other great_circle
functions.
Hope this helps,
Alexej Sveshnikov