MATLAB 'for' loop skipping IF statement - matlab

range = min(x):0.0001:max(x);
N = numel(range);
x = sort(x);
hit = 0;
i=1;
for j = 1:(N-1)
if range(j) <= x(i) && x(i) < range(j+1)
hit = hit + 1;
i = i+1;
if x(i) == x(i-1)
while x(i) == x(i-1) % If there are more than one of the same
hit = hit + 1; % numbers in succession, this allows x and
i = i+1; % hit to carry on incrementing.
end %while
end %if
end %if
end %for
disp(hit)
This code compares 'range' and 'x'. It checks to see if 'x' is between values in 'range', if so the 'hit' counter gets incremented and so does the current value of 'x'.
Problem is, on some random values of x (as far as I can tell they are random), although they should satisfy the inequality in the 'IF' statement, the 'IF' statement gets ignored, the for loop continues and thus the final 'hit' value is wrong.
'x' is usually a 1D array about a million or so wide.
for this example, let
`x = [-2.1792 -2.1759 -2.1758 -2.1748 -2.1658 -2.1648 -2.1646 -2.1604 -2.1603 -2.1550]`
'hit' should equal '10' but instead outputs '2' since it decides to skip the 'IF' statement at 'j=35'.
To clarify. When 'j=35', range(j) = -2.1758 and i=3 meaning x(i)=-2.1758
I'm pretty sure that:
range(j) <= x(i) && x(i) < range(j+1)
-2.1758 <= -2.1758 && -2.1758 < -2.1757 %**edited, meant -2.1757 not -2.1759**
Is true.
I hope I'm just doing something silly here that I can't see. Sorry if it's a badly formatted question, it's my first here.
Cheers in advance.

A subsequent number x(i) could pass this test:
if range(j) <= x(i) && x(i) < range(j+1)
Without actually being equal to its neighbor:
if x(i) == x(i-1)
It could be infinitesimally larger and thus you move to the next j and it is out of range. Your inner while needs the same condition as the outer if. And you can skip the if COND while COND and just do while COND since it will work the same.

Would the following code not be simpler, faster, and give the same result?
x = sort(x)
hit = sum(diff(x)==0);

Related

Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

MATLAB, fixed point iteration

I am given a function, f(x)= 5*sin(x)*exp(-x-0.2)-1, and I want to find a root using fixed point iteration. The instruction told me to re-arrange the equation to get x=g(x).
So I converted it to x=-ln[1/(5sin(x)]-0.2
I want to make a while loop that satisfies x(1+i)=g(i) relationship as I update x, until x converges. I am guessing that the 'converging' here means that abs(x(i)-x(i+1)) is very small, but not so sure.
x(1)=1;
while abs(x(i+1)-x(i)>0.0001 && i<50
g(i)=-log(1/(5*sin(x(i))))-0.2;
x(i+1)=g(i);
end
My code is obviously wrong. I know I have to update i like, i=i+1; somewhere, but I don't know how I should apply it. also, I see that I haven't declared x(1+1) in the beginning, and that's where I am getting an error from, but... no clue how to fix it.
please help.
If you want to do it in a while loop, then you need to do the first iteration outside the while loop:
x(1) = 1;
x(2) = -log(1/(5*sin(x(1)))) - 0.2;
i = 2;
max_iter = 50;
while (abs(x(i) - x(i-1)) > 0.0001) && (i < max_iter)
x(i+1) = -log(1/(5*sin(x(i)))) - 0.2;
i = i + 1;
end
Alternatively you could test for the number of elements of x in the while condition but that less elegant.
Put the test for convergence inside the loop since you have only one value of x to start with:
x(1) = 1;
max_iter = 50;
for i = 1 : max_iter
x(i+1) = -log(1/(5*sin(x(i)))) - 0.2;
if abs(x(i+1) - x(i)) < 0.0001
break; end
end

How to keep a constant value of a variable during the execution of the code in Matlab

I have a short (and I reckon silly as well) question about manipulation of variables in Matlab codes. How can I keep a constant value of a variable (assigned during the execution of the code), while the code executes further? So basically put the value into the memory and don't change it all. As an example of the code on which I am working right now:
if SystemTriggered ==1;
if Accelerationflag == 1;
for n = 1:1:100
AOrder = 1/2*HMSpeed^2/(Acc+n*2*pi);
if AOrder<Alim;
k = n;
Accelerationflag = 0;
break;
end
end
end
Offset = k;
AccOffset = PhaseIni - Offset*2*pi;
%Derivation conditions
if My condition here;
HmSpeedReached = 1;
end
end
So I am looking for an option, how I can keep the calculated value of "Offset" when I got "HmSpeedReached =1". Since we have a "for" cycle in the beginning (that will assign a value to K and then to Offset), so I just need to keep that number as a value of the variable all the time, after the condition of HmSpeedReached is satisfied...
Thank you in advance.
If I understand correctly then you want the following:
Keep assigning Offset = k whilst looping through your code
If HmSpeedReached = 1 has been set, then don't change the Offset value
This code (adapted from yours) should work
% Initially make sure HmSpeedReached is not equal to 1
HmSpeedReached = 0;
% Your code with addition...
if SystemTriggered ==1;
if Accelerationflag == 1;
for n = 1:1:100
AOrder = 1/2*HMSpeed^2/(Acc+n*2*pi);
if AOrder<Alim;
k = n;
Accelerationflag = 0;
break;
end
end
end
% Add a condition here to check if Offset should be updated, if HmSpeedReached is not 1
if HmSpeedReached ~= 1
Offset = k;
end
AccOffset = PhaseIni - Offset*2*pi;
%Derivation conditions
if My condition here;
HmSpeedReached = 1;
end
end
If instead you want to save a vector of Offset values, every time some condition is met, then use something like this:
Offset = [];
HmSpeedReached = 0;
if SystemTriggered ==1;
if Accelerationflag == 1;
for n = 1:1:100
AOrder = 1/2*HMSpeed^2/(Acc+n*2*pi);
if AOrder<Alim;
k = n;
Accelerationflag = 0;
break;
end
end
end
% Add a condition here to check if Offset should be updated, if HmSpeedReached is not 1
if CONDITION FOR SAVING OFFSET
Offset = [Offset, k];
end
AccOffset = PhaseIni - Offset*2*pi;
%Derivation conditions
if My condition here;
HmSpeedReached = 1;
end
end
Assign HmSpeedReached = 0 at the top and test for HmSpeedReached equal zero as a condition to change the variable Offset.

MATLAB - Condition to do something only once every x number of loops

I am trying to change the value of z by +1 every 750th, 1500th, 2250th,...,etc loop and this is what I have written:
len = 1500000;
y = 750;
z = 1;
for i = 1:len
if (i == [y.*(1:2000)])
z = z + 1;
end
end
Why is the value of z not changing? Can someone tell me what's wrong with my if statement please?
MATLAB only considers an array to be true if all elements are true. So with that in mind, if we look at your conditional for your if statement
i == (y .* (1:2000))
What this returns is an array of 2000 values where they are either all false (in the case where i isn't a multiple of y) and all false except for one true value when it is. Even when there is one true, this still evaluates to false and your if statement will never be evaluated.
A better way to do this is to use mod to check if a given i is a multiple of y
if mod(i, y) == 0
z = z + 1;
end
However, if the only contents of your loop are what you have shown, then you can simply omit the iterations that you don't care about
for i = y:y:len
z = z + 1;
end
If you actually do want to compare the array as you showed though, you'd be best to compute y .* 1:2000 outside of the loop and then use ismember to see if i is in the array
tmp = y .* (1:2000);
for i = 1:len
if ismember(i, tmp)
z = z + 1;
end
end

Conditional switching between vector

I have two same dimensioned vectors sig1 and sig2, both have more than 1 million data. With the condition that whenever the value of a vector falls below a threshold, a pointer will point to alternate vector (switching). This way I want to form a new vector sws from the pointer's values. Below code works fine, the only issue is, it takes long time. Is there any other way to speed up the code? :
thresh = -70;
i=1;
flag1 = 1; % 1 means sig1, 0 means sig2
flag2 = 0; % 1 means switch happened in this loop, 0 means no switch happened in this loop
while(i <= numel(sws))
if(flag1 == 1)
sws(i)=sig1(i);
else
sws(i)=sig2(i);
end
if(sws(i) < thresh)
if(flag2==1)
i=i+1;
else
flag1 = ~flag1;
end
flag2= ~flag2;
else
flag2 = 0;
i=i+1;
end
end