Matlab - Generating random numbers and counting - matlab

I need to create an experiment where I generate random numbers from 1 to 4 and stop when the numbers 1,2,3,4 appear at least once. Then I need to display the amount of random numbers.
I'm new to mathlab and so far I only have a vague idea on how to do this.
I think I need to create a counter for each number and stop when each one is atleast one.
y=randi([1,4]);
disp(y);
Generates 1 random number but I think I need to use a while loop to keep generating random numbers and break it when the counters are all >=1
Thanks

I think the following code will solve you problem.
counter = zeros(4, 1);
while ismember(0, counter)
y = randi([1, 4]);
counter(y) = counter(y)+1;
end
Counter contains the count for each number.

Yang Zhang's ^^ is much better
That solution will work! You could also use a vector to store the counters
X = zeros(1, 4);
count = 0;
while X(1) == 0 || X(2) == 0 || X(3) == 0 || X(4) == 0
r = randi([1,4])
if r == 1
X(1) = X(1) + 1;
elseif r == 2
X(2) = X(2) + 1;
elseif r == 3
X(3) = X(3) + 1;
elseif r == 4
X(4) = X(4) + 1;
end
count = count + 1;
end
disp(count)
there is probably a more elegant way to do this, but it is a small enough problem that efficiency is not an big issue

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 code to analyze data on a grid

I have a point set with (x,y) coordinates and their corresponding weights in matrix a where the 1st, 2nd and 3rd columns are x, y, and weight respectively. I want to divide this point set into grid cells, and count the number of points in each grid and the total weight of each grid.
I tried the small example below, but it did not work. Here I tried to divide this data set into a 2x2 small grid and tried to count number of points and their sum of weights. Further, I have big data set, so I can not extend this approach further when I need different step sizes for grid.
Can someone please help me to develop an easier approach?
function dataTree
count=zeros(9,1);
avg=zeros(9,1);
data=[1 3 100; 2 1 120; 3 5 110; 4 2 100; 5 3 150; 6 2 100];
for i=1:6
if data(i,1)<=2
for j=1:6
if data(j,2)<=2
count(1) = count(1) + 1;
avg(1) = avg(1) + data(j,3);
elseif data(j,2)<=4
count(2) = count(2) + 1;
avg(2) = avg(2) + data(j,3);
elseif data(j,2)<=6
count(3) = count(3) + 1;
avg(3) = avg(3) + data(j,3);
end
end
elseif data(i,1)<=4
for j=1:6
if data(j,2)<=2
count(4) = count(4) + 1;
avg(4) = avg(4) + data(j,3);
elseif data(j,2)<=4
count(5) = count(5) + 1;
avg(5) = avg(5) + data(j,3);
elseif data(j,2)<=6
count(6) = count(6) + 1;
avg(6) = avg(6) + data(j,3);
end
end
elseif data(i,1)<=6
for j=1:6
if data(j,2)<=2
count(7) = count(7) + 1;
avg(7) = avg(7) + data(j,3);
elseif data(j,2)<=4
count(8) = count(8) + 1;
avg(8) = avg(8) + data(j,3);
elseif data(j,2)<=6
count(9) = count(9) + 1;
avg(9) = avg(9) + data(j,3);
end
end
end
end
count'
avg'
If your x and y are not yet rounded to some arbitrary units, do so first:
x = round((x - min(x))/edgelength+1);
this makes sure that you obtain grid with edgelength sized squares, which is indicated by non-zero integers. Do the same for y.
Then you can use either sparse or accumarray to get the total weight. sparse is faster, but is less wide applicable:
gridWeight = sparse(x,y,weight);
if you want to get average weights, add 1 for each entry and divide by that matrix:
NumEntries = sparse(x,y,1);
MeanWeights = gridWeight./NumEntries;
accumarray can do both of these operations in one go:
gridWeight = accumarray([x y],weight);
MeanWeights = accumarray([x y], weight,[],#mean); %//add ,[], 'issparse' for sparse matrix
Note that sparse is a sub-functionality of accumarary by setting accumarray=([i,j],val,[],#sum,[],'issparse'). The only function sparse can handle is #sum and it's sole fill-value is 0, whilst for accumarray other functions and values can be used.

Only else part is being executed in If-else statement in matlab

I'm working on counting numbers using if-else statement. I'm getting the result, but it's only executing the else part and not looking at the other part.
This is the code I'm working with
i = 0;
j = 0;
if sum( abs( f1(:) - f2(:))) == 0.0
i = i + 1;
else
j = j + 1;
end
if sum(abs(f2(:) - f3(:))) == 0.0
i = i + 1;
else
j = j + 1;
end
if sum(abs(f3(:) - f4(:))) == 0.0
i = i + 1;
else
j = j + 1;
end
msgtext = sprintf('Matching = %d',i);
h = msgbox(msgtext);
msgtxt = sprintf(' Not Matching = %d',j);
h = msgbox(msgtxt);
Any suggestions?
Thanks in advance!
Your question is extremely vague so I'm going to pretend you only asked about one of the ifs:
if sum( abs( f1(:) - f2(:))) == 0.0
i = i + 1;
else
j = j + 1;
end
I think there is a fair chance that you only ever fall into the else clause because you are trying to equate floating point numbers, and that is a bad idea due to precision errors. This depends on the nature of f1 and f2, are they doubles, how were the calculated etc which you have given no indication of in your question. If you want to understand why you can't equate floating point numbers (or expect there difference to equal 0) then you must read What every computer scientist needs to know about floating-point arithmetic
Rather try if sum( abs( f1(:) - f2(:))) < tol where tol (i.e. tolerance) is a really tiny number (e.g. eps, but just choose a number that is orders of magnitude less than your application could produce.).

Gauss-Seidel code not converging on solution

I am unable to get converging values using a Gauss-Seidel algorithm
Here is the code:
A = [12 3 -5 2
1 6 3 1
3 7 13 -1
-1 2 -1 7];
b = [2
-3
10
-11];
ep = 1e-8;
[m, n] = size(A);
[n, p] = size(b);
x = zeros(n, 1001);
x(:, 1) = []
for k=0:1000
ka = k + 1;
if ka == 1001
break;
end
xnew = zeros(n,1);
for i=1:n
sum = 0;
j = 1;
while j < i
s1 = s1 + A(i,j) * x(j, ka + 1);
j = j + 1;
end
j = i + 1;
while j <= n
sum = sum + A(i,j) * x(j, ka);
j = j + 1;
end
xnew(i) = (b(i) - sum) / A(i, i);
% if result is within error bounds exit loop
if norm(b - A * xnew, 2) < ep * norm(b, 2)
'ending'
break
end
end
x(:,ka + 1) = xnew;
end
I cannot get the A * xnew to converge on b what am I doing wrong?
I have tried running this changing the syntax several times, but I keep getting values that are way off.
Thanks!
Gabe
You have basically two problems with your code:
(1) You are using two different variables "sum" and "s1". I replaced it by mySum. By the way, dont use "sum", since there is a matlab function with this name.
(2) I think there is also a problem in the update of x;
I solved this problem and I also tried to improve your code:
(1) You dont need to save all "x"s;
(2) It is better to use a "while" than a for when you dont know how many iterations you need.
(3) It is good to use "clear all" and "close all" in general in order to keep your workspace. Sometimes old computations may generate errors. For instance, when you use matrices with different sizes and the same name.
(4) It is better to use dot/comma to separate the lines of the matrices
You still can improve this code:
(1) You can test if A is square and if it satisfies the conditions necessary to use this numerical method: to be positive definite or to be diagonally dominant.
clear all
close all
A = [12 3 -5 2;
1 6 3 1;
3 7 13 -1;
-1 2 -1 7];
b = [2;
-3;
10;
-11];
ep = 1e-8;
n = length(b); % Note this method only works for A(n,n)
xNew=zeros(n,1);
xOld=zeros(n,1);
leave=false;
while(~leave)
xOld=xNew;
for i=1:n
mySum = 0;
j = i + 1;
while j <= n
mySum = mySum + A(i,j) * xOld(j,1);
j = j + 1;
end
j = 1;
while j < i
mySum = mySum + A(i,j) * xNew(j,1);
j = j + 1;
end
mySum=b(i,1)-mySum;
xNew(i,1) = mySum / A(i, i);
end
if (norm(b - A * xNew, 2) < ep * norm(b, 2))
disp('ending');
leave=true;
end
xOld = xNew;
end
xNew

How to specific not converging criterion of an iteration in matlab?

Hi everyone this is What I did to carry out an iteration method(gauss seidel) and I want when iteration number greater than 30 it will stop and generate the corresponding result up to 30 iteration. But I wonder why the output result were so weird and I try to check the value on the command window by typing x_ans(:,1) it gives me the correct value. It really made me frustrated why the generate result were not the same. Or any other circumstance or function can be used to set for not converging condition. Sincerely thanks in advance for every single help.
clear;clc
A = [2 8 3 1;0 2 -1 4;7 -2 1 2;-1 0 5 2]
B = [-2;4;3;5]
Es = 1e-5
n = length(B);
x = zeros(n,1);
Ea = ones(n,1);
iter = 0;
while max(Ea) >= Es
if iter <= 30
iter = iter + 1;
x_old = x;
for i = 1:n
j = 1:n;
j(i) = [];
x_cal = x;
x_cal(i) = [];
x(i) = (B(i) - sum(A(i,j) * x_cal)) / A(i,i);
end
else
break
end
x_ans(:,iter) = x;
Ea(:,iter) =abs(( x - x_old) ./ x);
end
result = [1:iter; x_ans; Ea]'
I've gone through the formulas and they are all OK. On a side note, the sum is not necessary. The problem lies with your input data - try reordering! check for example the following, which works
A = [7 -2 1 2;
2 8 3 1;
-1 0 5 2;
0 2 -1 4;]
B = [3;-2;5;4]
see the wiki under convergence.