Another Lesson in Floating Point
In an earlier post I discussed the issue of floating point accuracy in calculations. I have another example to share today that has been lurking in the Mapping Toolbox product. The issue is with the function wrapTo180.
Contents
Work-around
There is a work-around for those of you using Mapping Toolbox with releases R2007b and R2008a.
Numerical Issue
In R2007b and R2008a, the implementation for wrapTo180 causes results from wrapTo180(lon) to differ very slightly from lon even for for certain values of lon in the interval [-180 180]. The differences are on the order of 2*eps(lon).
Test Case
The following should evaluate to true.
lon = 115.8323;
but doesn't.
isequal(lon,wrapTo180(lon))
ans = 0
These quantities aren't equal because of the arithmetic being done: 115.8323 + 180 - 180 differs from 115.8323 by
(lon + 180 - 180) - lon
ans = 2.8422e-014
which happens to be
2*eps(lon)
ans = 2.8422e-014
The Code
Here's the code for wrapTo180
type wrapTo180
function lon = wrapTo180(lon) %wrapTo180 Wrap angle in degrees to [-180 180] % % lonWrapped = wrapTo180(LON) wraps angles in LON, in degrees, to the % interval [-180 180] such that 180 maps to 180 and -180 maps to -180. % (In general, odd, positive multiples of 180 map to 180 and odd, % negative multiples of 180 map to -180.) % % See also wrapTo360, wrapTo2Pi, wrapToPi. % Copyright 2007 The MathWorks, Inc. % $Revision: 1.1.6.2 $ $Date: 2007/08/20 16:35:59 $ lon = wrapTo360(lon + 180) - 180;
Simple Fix
We can just skip the arithmetic operation for values,like 115.8323, that already are in the interval [-180 180]. A nice way to do this is with logical indexing and we can replace the line of code with this.
q = (lon < -180) | (180 < lon); lon(q) = wrapTo360(lon(q) + 180) - 180;
Comments?
Have you ever had a similar issue, where a seemingly innocent code expression causes erroneous results? How have you found this out and solved it? I'd love to hear your thoughts here.