x = [1:0.1:10]
julia> x
91-element Array{Float64,1}:
1.0
1.1
1.2
1.3
1.4
⋮
9.4
9.5
9.6
9.7
9.8
9.9
10.0
It is very easy to find the indice of an exact value of x, for example 8.2
julia> find(x .== 8.2)
1-element Array{Int64,1}:
73
But if I want the indice of the closest value of 8.22
julia> minimum(abs(x-8.22))
0.02000000000000135
julia> find(x .== minimum(abs(x-8.22)))
0-element Array{Int64,1}
Of course it is easy to do that with a loop but is it the fastest solution ?
min_i = 0
min_x = 1.0
for i=[1:length(x)]
e = abs(collect(x)[i] - 8.22)
if e < min_x
min_x = e
min_i = i
end
end
println(min_x, " -> ", min_i)
0.02000000000000135 -> 73my loop solution :
0.000419 seconds (547 allocations: 708.797 KB)
0.02000000000000135 -> 73
x = [1:0.1:1000000]
val = 8.22
function dicotomy(x, val)
a = start(eachindex(x))
b = length(x)
j = length(x)
dxbest = abs(x[a]-val)
dx = dxbest
while true
dx < dxbest ? dxbest = dx : 1
j = round(Int,(a+b)/2)
dx = x[j]-val
x[j]-val < 0 ? a = j : b = j
abs(a-b) < 2 && break
end
return a,b
end
@time dicotomy(x, 8.22)
0.000004 seconds (5 allocations: 192 bytes)
(73,74)
@time searchsorted(x, 8.22)
0.000005 seconds (7 allocations: 240 bytes)
@time closest_index(x,8.22)
0.027618 seconds (4 allocations: 160 bytes)
73
julia> x = 1:0.1:1000000
1.0:0.1:1.0e6
julia> @time searchsorted(x, 8.22)
0.045590 seconds (33.21 k allocations: 1.535 MB)
74:73
julia> @time searchsorted(x, 8.22)
0.000005 seconds (8 allocations: 288 bytes)
74:73
julia> @time searchsorted(x, 8.22)
0.000005 seconds (8 allocations: 288 bytes)
74:73
julia> @time closest_index(x,8.22)
0.103219 seconds (4.37 k allocations: 222.884 KB)
73
julia> @time closest_index(x,8.22)
0.095684 seconds (4 allocations: 160 bytes)
73
julia> @time dicotomy(x, 8.22)
0.009142 seconds (3.45 k allocations: 173.973 KB)
(73,74)
julia> @time dicotomy(x, 8.22)
0.000005 seconds (5 allocations: 192 bytes)
(73,74)
julia> @time dicotomy(x, 8.22)
0.000004 seconds (5 allocations: 192 bytes)
(73,74)function mindist0(x, val)
# your original
min_i = 0
min_x = 1.0
for i=1:length(x)
e = abs(collect(x)[i] - val)
if e < min_x
min_x = e
min_i = i
end
end
return (min_i, min_x)
end
function mindist1(x, val)
# same as the original, except removing 'collect'
min_i = 0
min_x = 1.0
for i = 1:length(x)
e = abs(x[i] - val)
if e < min_x
min_x = e
min_i = i
end
end
return (min_i, min_x)
end
function mindist2(x, val)
# using enumerate to avoid indexing
min_i = 0
min_x = Inf
for (i, xi) in enumerate(x)
dist = abs(xi - val)
if dist < min_x
min_x = dist
min_i = i
end
end
return (min_i, min_x)
end
function test_dist(x, val, N)
# putting time testing inside a function for optimal result
@assert mindist0(x, val) == mindist1(x, val) == mindist2(x, val)
@time for _ in 1:N mindist0(x, val) end
@time for _ in 1:N mindist1(x, val) end
@time for _ in 1:N mindist2(x, val) end
end
>> test_dist(1:0.1:10, 8.22, 1)
0.000060 seconds (182 allocations: 76.781 KB)0.000001 seconds0.000001 seconds
>> test_dist(1:0.1:10, 8.22, 1)
0.641741 seconds (1.82 M allocations: 749.817 MB, 7.57% gc time)0.007380 seconds0.005570 seconds>> test_dist(1:0.1:10, 8.22, 1)0.641741 seconds (1.82 M allocations: 749.817 MB, 7.57% gc time)0.007380 seconds0.005570 seconds
>> test_dist(1:0.1:10, 8.22, 10^4)