Break statement in Matlab - matlab

For a certain number n I have to find the next greater number than n which is prime.
I had to solve this problem in Matlab.
Below is my code:
Solution1
function k = next_prime(n)
while n<10000000000
n=n+1;
if isprime(n)==true
k=n;
break
end
end
end
In this way the problem is correctly solved, but my initial solution was:
Solution2
function k = next_prime(n)
while n<10000000000
n=n+1;
if isprime(n)==true
k=n;
end
break
end
end
The only difference between Solution1 vs Solution2 is the break statement place.
Why Solution1 is ok and Solution2 is not ok?

The break statement in MATLAB
terminates the execution of a for or while loop. Statements in the loop after the break statement do not execute.
In solution 2 you are guaranteed to break at every loop iteration, not only if it is prime. Thus it will always only run the loop once, set n to n+1 and then break without setting k (unless coincidentally n+1 was prime).
It might help you to see it if you fix your indentation:
function k = next_prime(n)
while n<10000000000
n=n+1;
if isprime(n)==true
k=n;
end
break
end
end
so the loop does 3 things, it increments n, it checks if n is prime and then it exits, always.
In solution 1, you only exit if n is prime, which is obviously what you want.

Related

Matlab roll one dice game by using python and for sentence to add number

The question is this. As a result of consideration, I think if this condition is satisfied the code will be success.
Set n = 0, generate one of the integers 1~6 uniformly, Add a win if 1 was generated and add a lose otherwise, n++, 4. go back to 1 if n
but I don't know how to make it.can you please help me
N=100;
win=0;
lose=0;
a=randi([1 6],1,1);
n=0;
p=0;
while n<N
if a==1
win=win+1;
else
lose=lose+1;
n++
endif
endwhile
There are a couple of errors in your code:
you are generating only one random number, since the call to randi is outside of the while loop. So you are testing a==1 N times with a having always the same value
a part from the previous error, you are incrementing the counter n only in the else condition
A possible implementation could be the following in which you can incluide the code in a for loop to check the percentage of win wrt the number of attempts; you can also add the reference value of 1/6 %.
% Define the winning number
win_value=1
for N=1:1000
% Generate N random values
result=accumarray(randi([1 6],N,1),1);
% Count the wins
win(N)=result(win_value);
Pct_win(N)=win(N)/N*100;
end
plot(Pct_win)
hold on
plot([1 N],[1/6 1/6]*100,'r','linewidth',2)
xlabel('Attempts')
ylabel('Win %')
legend('Wins','Ref')

Too many input arguments error

I am trying to run my function. it shows
[root, ni]=value1(xu,xl,acceptable)
Error using value1
Too many input arguments.
function[root, ni]=value1(xu,xl,acceptable)
fu=HW10B(xu);
fl=HW10B(xl);
Err=1;
N=0;
if fu*fl>=0
end
while Err>=acceptable;
m=(xu+xl)/2;
fm=HW10B(m)
if fm*fu<0;
fl=m;
else fu=m;
Err=abs(xu-xl)/xu*100;
end
N=N+1;
end
function [ y] = HW10B( x)
%equation of x
y=3*x^3-8*x^2-4*x+9;
end
root=m;
ni=N;
end
function[m, N]=value1(xu,xl,acceptable)
y=#(x)3*x.^3-8.*x.^2-4.*x+9;%//Used anonymous function instead of private
fu=y(xu);%//Used above definition
fl=y(xl);
Err=1;%//Initialise error
N=0;%//Initialise counter
while Err>=acceptable && N<1e4;%//check for convergence
m=(fu+fl)/2;%//Get new midpoint
fm=y(m);%//Get value at midpoint
if fm*fu<0;%//Get left or right value to move
fl=m;
else
fu=m;
Err=abs(fu-fl)/fu*100;%//Calculate the error
end
N=N+1;%//Update iteration counter
end
end
Call it from the command line:
xu=15;xl=2;acceptable=1e-3;
[root, ni]=value1(xu,xl,acceptable)
root =
2.7554
ni =
29
As you can see I cleaned up your code quite a bit. Using the two separate storage variables at the end of the code was just taking up more space than necessary. The if statement fu*fl>0 did not do anything, thus I chucked it out. Finally, you needed to update your values in your functions, thus using the fl, fx and fm, not the xu and xl.
If you call the function exactly as I showed you from the command line (with your own values of course), it should not throw any errors.
What happens in your original code is that you calculate everything once for the input variables, get an error which is larger than acceptable and therefore executes again, taking the same input arguments, returning the same error as before, which is still larger than acceptable. This is what we call an infinite loop. I suggest you check for it using a maximum number of iterations, i.e.
while Err>=acceptable && N<1e4
and change the 1e4 to whatever maximum number of iterations you want to have. If you accidentally end up going infinite, this counter will kill it without having to resort to crtl-c or equivalents.

Idiomatic way of exiting from multiple nested loops?

The MATLAB documentation describes the break keyword thus:
break terminates the execution of a for or while loop. Statements in the loop after the break statement do not execute.
In nested loops, break exits only from the loop in which it occurs. Control passes to the statement that follows the end of that loop.
(my emphasis)
What if you want to exit from multiple nested loops? Other languages, such as Java, offer labelled breaks, which allow you to specify where the flow of control is to be transferred, but MATLAB lacks such a mechanism.
Consider the following example:
% assume A to be a 2D array
% nested 'for' loops
for j = 1 : n
for i = 1 : m
if f(A(i, j)) % where f is a predicate
break; % if want to break from both loops, not just the inner one
else
% do something interesting with A
end
end
% <--- the break transfers control to here...
end
% <--- ... but I want to transfer control to here
What is an idiomatic way (in MATLAB) of exiting from both loops?
I would say for your original specific example, rather use linear indexing and a single loop:
%// sample-data generation
m = 4;
n = 5;
A = rand(m, n);
temp = 0;
for k = 1:numel(A)
if A(k) > 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
break;
else
temp = temp + A(k);
end
end
Or the practically identical (but with less branching):
for k = 1:numel(A)
if A(k) <= 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
temp = temp + A(k);
end
end
I would think that this answer will vary from case to case and there is no general one size fits all idiomatically correct solution but I would approach it in the following way depending on your problem (note these all assumes that a vectorized solution is not practical as that is the obvious first choice)
Reduce the dimensions of the nesting and use either no breaks or just one single break (i.e. as shown above).
Don't use break at all because unless the calculation of your predicate is expensive and your loop has very many iterations, those extra iterations at the end should be practically free.
Failing that set a flag and break at each level.
Or finally wrap your loop into a function and call return instead of break.
As far as I know there are no such functionality built in. However, in most cases matlab does not need nested loops due to its support for vectorization. In those cases where vectorization does not work, the loops are mostly long and complicated and thus multiple breaks would not hinder readability significantly. As noted in a comment, you would not really need a nested loop here. Vectorization would do the trick,
m = 5;
n=4;
x = rand(m,n);
tmp = find(x>0.8, 1, 'first');
if (isempty(tmp))
tmp = m*n+1;
end
tmp = tmp-1;
tot = sum(x(1:tmp));
There might of course be people claiming that for loops are not necessarily slow anymore, but the fact remains that Matlab is column heavy and using more than one loop will in most cases include looping over non optimal dimensions. Vectorized solutions does not require that since they can use smart methods avoiding such loops (which of course does not hold if the input is a row vector, so avoiding this is also good).
The best idiomatic way to use Python (or poison of your choice) and forget all this but that's another story. Also I don't agree with the vectorization claims of the other answers anymore. Recent matlab versions handle for loops pretty quickly. You might be surprised.
My personal preference goes to raising an exception deliberately and cradling it within a try and catch block.
% assume A to be a 2D array
A = rand(10) - 0.5;
A(3,2) = 0;
wreaker = MException('Loop:breaker','Breaking the law');
try
for j = 1 : size(A,1)
% forloop number 1
for i = 1 : size(A,2)
% forloop number 2
for k = 1:10
% forloop number 3
if k == 5 && j == 3 && i == 6
mycurrentval = 5;
throw(wreaker)
end
end
end
end
catch
return % I don't remember the do nothing keyword for matlab apparently
end
You can change the location of your try catch indentation to fall back to the loop of your choice. Also by slaying kittens, you can write your own exceptions such that they label the exception depending on the nest count and then you can listen for them. There is no end to ugliness though still prettier than having counters or custom variables with if clauses in my opinion.
Note that, this is exactly why matlab drives many people crazy. It silently throws exceptions in a pretty similar way and you get a nonsensical error for the last randomly chosen function while passing by, such as size mismatch in some differential equation solver so on. I actually learned all this stuff after reading a lot matlab toolbox source codes.

parallel independent iteration of elements in an array

I want to iterate all the elements independently (same condition for all elements though). I want to stop the iteration when the value stops changing. I will post the part of my code. According to some research, I figured that it can also be done using parfor loop but i don't know how to implement it. Can anyone please correct my code? Thanks in Advance.
probability = (ones(1,2048) .* 1/2048);
Tij = sum(StateTransitionfwd); %gives us an array of 2048 elements.
probability = ((probability * StateTransitionbwd) - (Tij .* probability));
threshold = (ones(1,2048) .* 0.05);
old = zeros(1,2048);
new = zeros(1,2048);
while(1)
probability = ((probability * StateTransitionbwd) - (Tij .* probability));
new = probability;
if old-new <= threshold
break
end
old = probability;
end
So basically I want the steady state probability (where it is not changing anymore)
For one you cannot parallellise while loops.
To implement a parfor loop make sure of the following:
- All variables must be defined before the parfor loop. Thus define output variables before the loop.
- All iterations must be absolutely independent of one another.
The second condition is not fulfilled in your case, since you are constantly updating the variable new, making it not independent.
I'd not even parallellise this code, since it's designed to break up before it went through all elements, but for the sake of argument I'll try this:
parfor ii = 1:length(Tij)
probability{ii} = ((probability * StateTransitionbwd) - (Tij .* probability));
end
Either use a cell or a matrix, whichever is more useful for your work.
Now you can go ahead and use a simple if to find your threshold:
for ii = 1:length(probability)-1
if probability(ii+1)-probability(ii)<threshold
break
end
end
As for your while loop stop condition: it's dangerous to let a loop run uncontrolled to some condition, as you do. It's rather easy to get stuck in an infinite loop. Use an additional condition MaxIt for the maximum number of iterations to do before terminating, regardless of the other condition.
while probability<threshold && MaxIt<someNumber
your code
end
Also you are checking for the validity of a full array.
A = logical([1;0]);
while A
B=1;
end
C = logical([1;1]);
while C
D=1;
end
The first while loop will not run, since one of its entries is not true; the second loop is an infinite loop now. If you want to terminate each row as soon as the condition is met, put the while loop inside a for loop over each row instead. That forloop can be parallellised if you put the while loop into a function, see the parfor documentation for that.

Break nested loop

I have three nested loop in Matlab and in each loop, I have an "if" that check a flag. If it was OK, the the algorithm proceeds, otherwise, I want that the program should be terminated. Here is my codes, I think something is wrong!
[A] = finction (...,...,...)
for i = 1:100
for j = 1:100
for k = 1:30
some operation which its results is a flag
if flag==1 % its initial value is 0
break
end;
end;
end;
end;
Where is should put that break in order I break the rest of the computations?
BREAK terminates the execution of a loop, so if you have a nested loop, break will only quit the innermost loop, and the program will continue running.
If you want the entire function to be terminated, you need to use RETURN. Please note that at the moment return is called, all the requested output arguments must be assigned to some value, otherwise the code will throw an error.