Reputation: 709
I've written a function which generates a discrete random variable and returns two indices.It seems that my code is wrong because the returned first index is always 4. Here is my code:
function inds(arr::Array{Float64, 2})
probs = arr/sum(arr)
u = rand()
sum_prob = 0.0
local ii, jj
for i=1:size(arr)[1]
for j=1:size(arr)[2]
if sum_prob <= u < sum_prob + probs[i,j]
ii = i
jj = j
break
else
sum_prob += probs[i,j]
end
end
end
return (ii, jj, probs[ii,jj])
end
Upvotes: 4
Views: 87
Reputation: 33249
In this particular case because the two loops can be combined into one multi-iterator loop you can break them both if you do that:
function inds(arr::Array{Float64, 2})
probs = arr/sum(arr)
u = rand()
sum_prob = 0.0
local ii, jj
for i=1:size(arr,1), j=1:size(arr,2)
if sum_prob <= u < sum_prob + probs[i,j]
ii = i
jj = j
break
else
sum_prob += probs[i,j]
end
end
return (ii, jj, probs[ii,jj])
end
Note that since arrays are column-major in Julia—like Fortran and Matlab, but unlike C—it is probably faster to switch the loop order like this:
function inds(arr::Array{Float64, 2})
probs = arr/sum(arr)
u = rand()
sum_prob = 0.0
local ii, jj
for j=1:size(arr,2), i=1:size(arr,1)
if sum_prob <= u < sum_prob + probs[i,j]
ii = i
jj = j
break
else
sum_prob += probs[i,j]
end
end
return (ii, jj, probs[ii,jj])
end
Upvotes: 5
Reputation: 26886
Most likely, you do need to break from both loops. The standard way to do this is to use a boolean flag to exit from both loops, e.g.:
function inds(arr::Array{Float64, 2})
is_done = false
probs = arr/sum(arr)
u = rand()
sum_prob = 0.0
local ii, jj
for i=1:size(arr)[1]
for j=1:size(arr)[2]
if sum_prob <= u < sum_prob + probs[i,j]
ii = i
jj = j
is_done = true
break
else
sum_prob += probs[i,j]
end
end
if is_done:
break
end
end
return (ii, jj, probs[ii,jj])
end
Upvotes: 4