Why are the variables declared in this WHILE loop not getting modified in the FOR loop?
3 次查看(过去 30 天)
显示 更早的评论
So, I'm helping a friend put together a function that essentially carries out a tour-de-wino style random walk. What it should do is run "walks" number of random walks, and in each walk, take "steps" number of steps of step size "step" until it hits the boundaries (the lines that form a square that starts at (0,0) and ends at (1,1). Unfortunately, it does not do this--in fact, it doesn't seem to modify the coordinates of the wino at all! Why is that?
the code is as follows (slightly reformatted to display properly in the post):
function [count] = random_walk( step, walks, steps )
% Only works for domains from 0 to 1, in steps of powers of 10
count = zeros(1/step, 4);
fail = 0;
j = 0;
while j < walks
locumx = 0.5;
locumy = 0.5;
directions = randi(4,1, steps);
for i = [1:steps+1]
if (i == (steps+1)) && ((locumx ~= 1) || (locumx ~= 0)) || ((locumy ~= 1) || (locumy ~= 0))
%j = j-1;
fail = fail +1;
break
elseif (i == (steps+1)) && ((locumx == 1) || (locumx == 0)) || ((locumy == 1) || (locumy == 0))
display(num2str(j+1), 'th walk completed successfully')
break
else
if directions(i) == 1
locumy = locumy + step;
if locumy == 1
count(locumx/step,1) = count(locumx/step,1) + 1;
break
end
elseif directions(i) == 2
locumy = locumy - step;
if locumy == 0
count(locumx/step,2) = count(locumx/step,2) + 1;
break
end
elseif directions(i) == 3
locumx = locumx + step;
if locumx == 1
count(locumy/step,3) = count(locumy/step,3) + 1;
break
end
elseif directions(i) == 4;
locumx = locumx - step;
if locumx == 0
count(locumy/step,4) = count(locumy/step,4) + 1;
break
end
else
display('drats')
end
end
end
j = j+1;
end
dumb = num2str(fail);
display(strcat('This function failed this many walks: ', dumb))
display(locumx, 'x')
display(locumy,'y')
end
2 个评论
Jan
2015-4-6
count = zeros(1/step, 4);
This works only if step|is smaller equal 1 and if |1/step is an integer without rounding.
for i = [1:steps+1]
This loop has 1 iteration only with i==1, because step must be smaller then 1.
采纳的回答
Stephen23
2015-4-4
编辑:Stephen23
2015-4-6
Based on the comment given to my first answer: "take steps in 1 of 4 directions", it seems that the direction should be limited to orthogonal directions only:
mxS = 20;
wlk = 10;
stp = 2.5 - randi(4,mxS,wlk);
drn = abs(stp)>1;
poX = cumsum([zeros(1,wlk); drn.*sign(stp)]);
poY = cumsum([zeros(1,wlk);~drn.*sign(stp)]);
plot(poX,poY,'x-')
axis equal
Produces this figure:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/175837/image.jpeg)
And of course we can still find out which steps are inside the boundary:
>> box = 5;
>> idx = abs(poX)<box & abs(poY)<box
>> idx(~cumprod(+idx,1)) = false
and which walks reached the boundary:
>> any(~idx)
ans =
1 0 0 0 0 0 0 1 0 0
and in how many steps:
>> sum(idx,1)
ans =
15 21 21 21 21 21 21 12 21 21
Which tells us that only two of the ten walks reached the boundary, and the shortest walk was twelve steps. And of course we can easily print summaries, etc:
>> fprintf('%i paths did not reach the boundary\n',sum(any(~idx)))
2 paths did not reach the boundary
No loops: Faster, Neater, Easier!
0 个评论
更多回答(2 个)
Michael Haderlein
2015-4-1
编辑:Michael Haderlein
2015-4-1
Check line 11:
if (i == (steps+1)) && ((locumx ~= 1) || (locumx ~= 0)) || ((locumy ~= 1) || (locumy ~= 0))
You have 5 conditions here which group to 3 conditions:
(i == (steps+1))
&&
((locumx ~= 1) || (locumx ~= 0))
||
((locumy ~= 1) || (locumy ~= 0))
Of course, conditions 2 and 3 are always true (locumx cannot be both 1 and 0). So you have something like false && true | | true. Such statements are evaluated left to right, thus you have
false && true -> false;
false | | true -> true.
Therefore, it will always fail in the very first step. I guess you wanted to have the brackets a bit different.
Another remark, you always compare the positions locumx/locumy with zero and one. However, most likely the step will not exactly hit zero/one. Better compare with >=1 and <=0.
3 个评论
Michael Haderlein
2015-4-1
Well, I doubt it will ever hit 0 or 1. See my following example:
>> stepsize=1e-4;
>> pos=.5;
>> while pos(end)<=1
pos(end+1)=pos(end)+stepsize;
end
>> pos([end-2:end])
ans =
0.9999 1.0000 1.0001
>> 1-pos(end-1)
ans =
5.5067e-14
>> any(pos==1)
ans =
0
(Please don't take this as good programming style, I just want to keep the example simple as possible)
You see, I just add 1e-4 in a loop and store all positions. Also, the second-last value seems to be 1. However, it's not and none of the pos is exactly 1. In floating point arithmetics, you better don't compare with equality. If equality is necessary, use a domain (x>1-1e-4 && x<1+1e-4 for instance).
Stephen23
2015-4-1
编辑:Stephen23
2015-5-22
Rather than doing this in a loop, which will be very slow and inefficient use of MATLAB, you should learn how to write vectorized code, which will be much faster, neater, and less buggy than doing this in a loop.
For example this is the complete code needed to generate and plot some random walks with a constant step-size and a random direction:
mxS = 20;
wlk = 10;
ang = 2*pi*rand(mxS,wlk);
poX = cumsum([zeros(1,wlk);cos(ang)]);
poY = cumsum([zeros(1,wlk);sin(ang)]);
plot(poX,poY,'x-')
axis equal
Where each column of poX and poY are the x and y positions for one walk. The plot look like this:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/175750/image.jpeg)
This has a step-size of one and the walks all start at the origin: doing this makes detecting the bounding box-intersection much easier as the bounding box can then be a simple positive value allowing a basic logical conditional to detect that the path is still inside the bounding box:
>> box = 5;
>> idx = abs(poX)<box & abs(poY)<box;
>> idx(~cumprod(+idx,1)) = false;
where the values of idx indicate whether the step is inside the box, and again each column corresponds to one walk. We can then use any to check which walks reached the bounding box:
>> any(~idx,1)
ans =
1 1 0 0 0 0 1 1 0 1
This tell shows clearly that five of these ten random trials trials reached the box. You can count how many steps were required by summing these indices:
>> sum(idx,1)
ans =
12 11 21 21 21 21 15 20 21 18
The shortest path to the boundary was only eleven steps. Note how the values correspond to the logical values above.
No loops: Faster, Neater, Easier!
4 个评论
Stephen23
2015-4-4
编辑:Stephen23
2015-4-4
@Keane Sanders: as you only provided some non-functioning code and no specifications I had to make some assumptions about what you were actually trying to achieve. If you provided some clear specifications then it would be possible to show you a neat and robust way to code this problem. Saying that it "doesn't do what I need it to do" is fine, but in order to be able to give you the best advice we also need a description of what your aim is: you know what the code is supposed to do, but we don't (as we can't read minds).
Your comment indicates that you only wish to consider directions parallel to the axes, in this case you could consider my second answer...
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Graphics Performance 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!