How to read specific lines with Matlab - matlab

Here is what my data file looks like:
1
num num num
num num num
num num num
num num num
num num num
2
num num num
num num num
num num num
num num num
num num num
3
num num num
num num num
num num num
num num num
num num num
.
.
.
1000
num num num
num num num
num num num
num num num
num num num
'num' refers to a different float number, and 1,2,3,...,1000 are also part of the file, occupying one line each. What I want to do is, I need a loop from time step 1 to 1000, and during each step, I need to read the 3-column float number block below it as three column vectors. Then I proceed to the next time step, and read the block below, until I finish reading all.
How could I do this file reading with Matlab? In short, what I want to do is to read line 2 to line 6 as a matrix, then line 8 to line 12 as a matrix, then line 14 to 18 as a matrix, and so on...
Thanks!

You can read the text file as follows:
%Open text file
f = fopen('num.txt', 'r');
num_matrices = 1000;
%Initialize cell array - hold matrices.
C = cell(num_matrices, 1);
for i = 1:num_matrices
%Read index (to be ignored).
idx = fscanf(f, '%f', 1);
%Read 6x3 matrix into A
A = fscanf(f, '%f', [3, 6])';
%Store matrix in cell array C.
C{i} = A;
end
fclose(f);
Refer to https://www.mathworks.com/help/matlab/ref/fscanf.html for fscanf documentation.

Related

Octave/MATLAB Function to Convert Roman Numeral Into Decimal Number

I'm trying to write a function in Octave to convert roman numerals into decimal numbers.
What I have so far has two major problems:
1) It will only work for roman numerals up to 6 letters in length
2) The answer is only correct if each letter is smaller than the previous. ie it will not compute (IV) correctly as 4, but incorrectly as 6.
I need to somehow fix both of these problems. I have a strong suspicion that my approach to the problem is wrong and that there is an altogether more efficient way of doing this.
Anyway, if the problem interests you and/or you know of a good way to do this, any help is much appreciated.
function roman2num(s)
decimal = [1000, 500, 100, 50, 10, 5, 1];
roman = ["M", "D", "C", "L", "X", "V", "I"];
num = 0;
for i = 1:7
if strcmp(s(1), roman(i))
num += decimal(i);
break
end
end
if length(s) >= 2
for i = 1:7
if strcmp(s(2), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 3
for i = 1:7
if strcmp(s(3), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 4
for i = 1:7
if strcmp(s(4), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 5
for i = 1:7
if strcmp(s(5), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 6
for i = 1:7
if strcmp(s(6), roman(i))
num += decimal(i);
break
end
end
end
num
end
As far as I can tell the only rule you need to worry about is determining if the letter constitutes an "add" or "subtract" operation. For some letter, we only subtract it if the first non-equal letter to the right represents a greater value.
For example in 'IIV' The first non-equal letter to the right of both I's is V so we subtract 2 and add 5 for the V since it has no letters to the right.
Implementing this rule in MATLAB is fairly straightforward.
function num = roman2num(s)
decimal = [1000, 500, 100, 50, 10, 5, 1];
roman = ['M', 'D', 'C', 'L', 'X', 'V', 'I'];
tokens = arrayfun(#(x) decimal(find(roman==x,1)), char(s));
num = tokens(end);
for idx = 1:numel(tokens)-1
val = tokens(idx);
ridx = find(tokens(idx+1:end) ~= val, 1);
if ~isempty(ridx) && tokens(ridx + idx) > val
num = num - val;
else
num = num + val;
end
end
I tested using all the numerals between 1 and 3333.

Matlab programming error

I am trying out the questions in programming assignment of Coursera course on Matlab programming as an exercise. This is for my self-study.
Question:
Write a function called classify that takes one input argument x. That
argument will have no more than two dimensions. If x is an empty
matrix, the function returns -1. If x is a scalar, it returns 0. If x
is a vector, it returns 1. Finally, if x is none of these, it returns
2. Do not use the built-in functions isempty, isscalar, or isvector.
My code snippet:
function num = classify(x)
num = -1;
if(x == 3.14159265358979)
num = 0;
elseif(size(x, 2) == 3)
num = -1;
end
end
I got the below result on Matlab.
Problem 4 (classify):
Feedback: Your function performed correctly for argument(s) []
Feedback: Your function performed correctly for argument(s) zeros(1,0)
Feedback: Your function performed correctly for argument(s) zeros(0,4)
Feedback: Your function performed correctly for argument(s) 3.14159265358979
Feedback: Your function made an error for argument(s) [1 2 3]
Am I doing something wrong for arguments [1 2 3]?
If all you want is the code, I'll provide you with the answer, but I suggest you sit down and try to understand how and why this codes solves the problem, I'm guessing you want to learn something from it. Well, here's the code:
function [num] = classify(x)
if numel(x) == 0
num = -1;
return
end
num = sum(size(x) > 1);
end
You can most easily check if x is empty or a scalar by counting the number of elements (i.e. use the numel function). Then to determine if it is a vector or a higher dimensional matrix you need to check if the number of dimensions is less than 3 (this is because ndims returns 2 for both 1D and 2D matrices) and also verify that at least one of the first two dimensions has a size of 1:
function num = classify(x)
n = numel(x);
if n < 2
num = n-1;
else
if ndims(x) < 3 && any(size(x) == 1)
num = 1;
else
num = 2;
end
end
end
You should aim to write a generic function, your function would not work for example for any scalar input than pi.
Use the size function to determine the dimensions of the input, for example:
>> size([])
ans = 0 0
>> size(5)
ans = 1 1
>> size([5 6 7])
ans = 1 3
>> size([5;6;7])
ans = 3 1
Based on this, your function could looke like this:
function [num] = classify(x)
s = size(x);
if s == [0 0]
num = -1;
elseif s == [1 1]
num = 0;
elseif sort(s) == [1 3]
num = 1;
else
num = 2;
end
end
Yes, you tring to compare an array with a float.
It allows to do that (programaticalyl wrong) thing for [] because the array is empty
And for zeros, because the array is empty again: in the first case 0 columns, and in the second 0 rows
function i=classify(x)
[m, n]=size(x);
if n==1 && m==1
i=0;
elseif (m==0 && n==0)|| (m>=1 && n==0) || (m==0 && n>=1)
i=-1;
elseif (n>=1 && m==1) || (n==1 && m>=1)
i=1;
else i=2;
end
function y=classify(x)
[a b]=size(x);
%check for empty matrix
% Do not forget that an empty matrix can be size a x 0 or 0x a, where a can be
% arbitrary number
if (a>0)&&(b==0)||(a==0)&&(b>0)||(a==0)&&(b==0)
y=(-1);
%check for scalar
elseif (a==1)&&(b==1)
y=0;
%check for vector
elseif (a>=1)&&(b==1)||(a==1)&&(b>=1)
y=1;
%other case
else
y=2;
end

How to keep track of recursive call on my function collatz?

I am trying to keep track of how many times the function call itself. I have tried setting up num as 0 and putting num = num+1 at the end but I keep getting 1. How do I fix this?
function [out num] = collatz(val)
num = 0;
if val == 1
out = 1;
elseif mod(val, 2) == 0
out = collatz(val/2);
else
out = collatz(3*val+1);
end
num = num+1;
end
Thank you.
A possible approach is to use a global variable to count the number of calls. You need to declare that variable as global
in the workspace from which you call collatz the first time; and
within the function.
The function is thus defined as:
function out = collatz(val)
global num %// declare as global within the function
num = num+1; %// increase call counter
if val == 1
out = 1;
elseif mod(val, 2) == 0
out = collatz(val/2);
else
out = collatz(3*val+1);
end
end
And then, from the command line:
>> clear all
>> global num %// declare as global in workspace
>> num = 0; %// initiallize to 0
>> collatz(5)
ans =
1
>> num %// see value of num
num =
6
When you recursively call collatz you should save num too.
[out,num] = collatz(val/2);
You can also avoid using global declarations by changing your recursive calls in collatz so that they output num as well. You'll also need to change the base case so that num = 0 when val = 1. Therefore, do this instead:
function [out,num] = collatz(val)
if val == 1
out = 1;
num = 0; %// Change
elseif mod(val, 2) == 0
[out,num] = collatz(val/2); %// Change
else
[out,num] = collatz(3*val+1); %// Change
end
num = num+1;
end
You can then use collatz so that num is also output when you call it in the command prompt. When I do this, and calling collatz with 5, I get:
[out,num] = collatz(5)
out =
1
num =
6

matlab - find index for when values exceeds a threshold n number of times

I would like to find the index for when an array exceeds a certain value, and this value is value is exceeded for a duration, n. For examples:
n = 5;
dat = [1,2,2,1.5,2,4,2,1,1,3,4,6,8,4,9];
Here, I would like to find when 'dat' exceeds 2 for a duration greater than n for the first time. So, the solution here should lead to an answer:
ans = 10
Another example:
n = 7;
dat = [1,1,2,3,4,5,6,7,8,9,9,6,4,3,2,4,6,7,7,5];
find the first time that 'dat' exceeds or equals 5 for more than or equal to n times.
ans = 6
n = 5;
m = 2;
dat = [1,2,2,1.5,2,4,2,1,1,3,4,6,8,4,9];
c = conv(double(dat >= m), ones(1, n))
%I think you can also do
% c = conv((dat >= m)*1, ones(1, n))
min(find(c == n)) - n + 1
n=5
x=2;
dat = [1,2,2,1.5,2,4,2,1,1,3,4,6,8,4,9];
vec= cumsum(dat>=x);
ind=find(vec>=n);
ind=dat(ind(1));
ind will contain the answer 10

C / Generate a random number between 1 to 4 leaving 3 out with arc4random( )?

I have
int y = (arc4random()%4)+1;
So it generates a random number from 1 to 4.
I wanted to ask if there's a way to leave number 3 out so only numbers 1, 2 and 4 have a chance to get generated.
Thank you!
int allowdNumbers[3] = {1, 2, 4}
int index = arc4random()%3;
int number = allowdNumbers[index];
You can always make a random from 0-2 (arc4random() % 3) and use that number with 2 as a power:
2^0 = 1
2^1 = 2
2^2 = 4
and there you got your random from 1-4 without 3. In C:
int y = 1 << (arc4random() % 3);
Generate a random number from 0 to the number of different numbers you have (exclusive, and in your case, 3), and distribute the result according to your preference. In your case:
int y = (rand() % 3) + 1;
if (y == 3)
y++;
Assuming you want numbers that correspond to powers of two, then this should work nicely.
int y = 1 << arc4random_uniform(3);
If you want to leave out 3 for some other reason, then that would probably to more to obfuscate what you are doing than. In that case, something more straightforward would suffice.
do {
int y = arc4random_uniform(4) + 1;
} while (y == 3);
You can do this:
int y = (arc4random()%3)+1;
if (y == 3) y =4;
Though you should arc4random_uniform instead of the modulo operator.