Skip to content

Commit 15b5cfe

Browse files
authored
Merge pull request #80 from juliohm/haversine-floating-point
Handle floating point errors in Haversine distance
2 parents 2b0ab92 + 5b62efe commit 15b5cfe

File tree

2 files changed

+7
-4
lines changed

2 files changed

+7
-4
lines changed

src/haversine.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ end
1212

1313
const VecOrLengthTwoTuple{T} = Union{AbstractVector{T}, NTuple{2, T}}
1414

15-
function evaluate(dist::Haversine, x::VecOrLengthTwoTuple, y::VecOrLengthTwoTuple)
15+
function evaluate(dist::Haversine, x::VecOrLengthTwoTuple, y::VecOrLengthTwoTuple)
1616
length(x) == length(y) == 2 || haversine_error()
1717

1818
@inbounds begin
@@ -28,12 +28,14 @@ function evaluate(dist::Haversine, x::VecOrLengthTwoTuple, y::VecOrLengthTwoTupl
2828

2929
# haversine formula
3030
a = sin(Δφ/2)^2 + cos(φ₁)*cos(φ₂)*sin(Δλ/2)^2
31-
c = 2atan2(a, (1-a))
31+
32+
# take care of floating point errors
33+
a = min(a, one(a))
3234

3335
# distance on the sphere
34-
c*dist.radius
36+
2*dist.radius*atan2(a, (1-a))
3537
end
3638

3739
haversine(x::VecOrLengthTwoTuple, y::VecOrLengthTwoTuple, radius::Real) = evaluate(Haversine(radius), x, y)
3840

39-
@noinline haversine_error() = throw(ArgumentError("expected both inputs to have length 2 in Haversine distance"))
41+
@noinline haversine_error() = throw(ArgumentError("expected both inputs to have length 2 in Haversine distance"))

test/test_dists.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ end #testset
284284
@test haversine([0.,-90.], [0.,90.], 1.) π atol=1e-10
285285
@test haversine((-180.,0.), (180.,0.), 1.) 0 atol=1e-10
286286
@test haversine((0.,-90.), (0.,90.), 1.) π atol=1e-10
287+
@test haversine((1.,-15.625), (-179.,15.625), 6371.) 20015. atol=1e0
287288
@test_throws ArgumentError haversine([0.,-90., 0.25], [0.,90.], 1.)
288289
end
289290
end

0 commit comments

Comments
 (0)