Given a signed integer x, how could I convert this into a date relative to year 1, day 1 (like to_date in SQL) with the formatting day/month/year. My pseudocode solution for dealing with positive values was easy (but not elegant):
while x > 0
if(x > 364)
if (leap_year(year))
x -= 366
else
year += 1
else
for (i = 12; i > 0; i++)
if days_to_month[i] < x
month = i + 2
day += x - days_to_month[i]
x = 0
else if days_to_month[i] == x
month = i + 1
day = 1
x = 0
else if days_remaining < 31
month = 1
day = 1
x = 0
return (day, month year)
Like I said, it is a very messy solution but I'm not too worried for the time being. I am currently working on a way to represent negative values as BC dates.
This function currently doesn't support negative inputs and that is my end goal. I can't really wrap my head around how to write this and haven't been able to find a solution online that doesn't use an external library (I am trying not to use one).
Related
For this function:
y(t) =(sum from -inf to +inf) y[n]*p(t-nTs)
I wrote :
%main function
function project(arr,n,t,Ts)
symsum(arr(n)*p(t,-n*Ts),n,-inf,inf)
end
function rValue = p(t,Ts)
%standard square pulse of duration Ts:
if t<=(Ts/2)&& t>=(-Ts/2)
rValue = 1;
return
%standard triangular pulse of duration 2Ts:
elseif t<=Ts && t>=-Ts
rValue = (1-(abs(t)/Ts));
return
%truncated ideal pulse:
elseif t <=(3*Ts) && t>=(3*Ts)
rValue = sin(pi*t/Ts)/(pi*t/Ts);
return
%a pulse signal consisting of three parabolic segments
elseif t==no idea
rValue = no idea;
return
else
rValue = 0;
return
end
end
after function I have to create an array but what the assignment wants is like y[-3] . How is this possible to write -3 index to an array. Like :
y[-3] = 1st digit of ID number (leftmost digit)
y[-2] = -2nd digit of ID number
y[-1] = 0
y[0] = 3rd digit of ID number
y[1] = -4th digit of ID number
y[2] = 5th digit of ID number
y[3] = 0
y[4] = -6th digit of ID number
y[5] = 7th digit of ID number
y[6] = 8th digit of ID number (rightmost digit)
y[n] = 0 otherwise (-inf < n < inf)
If you absolutely need something that can be indexed using negative numbers you can use key-map pairs. Unfortunately, this method requires you to index using a char indicated by the single quotes ''. I would advise against typically indexing with negatives but this may help in your case. Also, you can evaluate this summation from the range n = -3 to n = 6 since the multiplication everywhere else outside that range is effectively zero.
Key-Map Pairs:
Keys = {'-3','-2','-1','0','1','2','3','4','5','6'};
Digits = [1 -2 0 3 -4 5 0 -6 7 8];
y = containers.Map(Keys,Digit);
y('-3')
y('-2')
y('-1')
y('0')
y('1')
y('2')
y('3')
y('4')
y('5')
y('6')
Alternatively by Using Anonymous Functions:
Thanks to #Hoki for this amazing alternative solution. It remaps the negative indices by using an anonymous function.
y = [1 -2 0 3 -4 5 0 -6 7 8];
idx = #(n) n+4;
y(idx(-3))
y(idx(-2))
y(idx(-1))
y(idx(0))
y(idx(1))
y(idx(2))
y(idx(3))
y(idx(4))
y(idx(5))
y(idx(6))
Ran using MATLAB R2019b
I have three vectors of the same size, pressure, year and month. Basically I would like to create a matrix of pressure values that correspond with the months and years that they were measured using a for loop. It should be 12x100 in order to appear as 12 months going down and 100 years going left to right.
I am just unsure of how to actually create the matrix, besides creating the initial structure. So far I can only find pressure for a single month (below I did January) for all years.
A = zeros([12, 100]);
for some_years = 1900:2000
press = pressure(year == some_years & month == 1)
end
And I can only print the pressures for January for all years, but I would like to store all pressures for all months of the years in a matrix. If anyone can help it would be greatly appreciated. Thank You.
Starting with variables pressure, year, and month. I would do something like:
A fairly robust solution using for loops:
T = length(pressure); % get number of time periods. I will assume vectors same length
if(length(pressure) ~= T || length(month) ~= T)
error('length mismatch');
end
min_year = min(year); % this year will correspond to index 1
max_year = max(year);
A = NaN(max_year - min_year + 1, 12); % I like to initialize to NaN (not a number)
% this way missing values are NaN
for i=1:T
year_index = year(i) - min_year + 1;
month_index = month(i); % Im assuming months run from 1 to 12
A(year_index, month_index) = pressure(i);
end
If you're data is SUPER nicely formatted....
If your data has NO missing, duplicate, or out of order year month pairs (i.e. data is formatted like):
year month pressure
1900 1 ...
1900 2 ...
... ... ...
1900 12 ...
1901 1 ...
... ... ...
Then you could do the ONE liner:
A = reshape(pressure, 12, max(year) - min(year) + 1)';
So I have to generate a random number (called 'p' here) between 0 and 90 whose frequency distribution is a cosine function (i.e I should have more numbers between 0 and 45 than numbers between 45 and 90).
I am working on matlab
The code is as follows -
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
end
end
I am generating 20 such numbers but always I get most of the numbers towards the higher end (45-90).
From those 20 numbers, there is hardly 1-2 numbers < 45.
Is my code wrong?
EDIT: Okay, so I got the answer. I tried running the code separately as follows-
for i = 1:20
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
disp(p);
end
end
end
And I'm getting most of the values of p between 0 and 45. My original code had an external 'if' condition which was the reason for only accepting higher values of 'p'. I used a while loop and the number of iterations were much more than 20 to get 20 values of 'p'.
Here is my original code snippet -
while zz <=20
d = randi([0,359]);
flag = 1;
while flag == 1
c = randi([0,90]);
x = rand(1);
if x < cosd(c)
p = c;
flag = 2;
end
end
if 'external condition'
strike(zz) = d;
dip(zz) = p;
slip(zz) = round(i);
zz= zz+1;
end
end
If you just want to get answer, read the last line. But if you want to know that why that answer is right, read the explanation.
Assume that you have a distinct distribution function like this:
f(0)=1;
f(1.5)=10;
f(4)=9;
So the cumulative function is:
F(0)=1;
F(1.5)=11;
F(4)=20;
No we want to have a relative cumulative function, as F(4)=20 (4 is the last item), we divide cumulative function by 20. So it would be:
F'(0)=0.05
F'(1.5)=0.55
F'(4)=1.00
Now, we generate a random number between 0 and 1. Every time we generate a random number, we generate a value for F'(x) and if F'(x) does not have that value anywhere, we use nearest bigger number (like y) which for some x, F(x)=y. For my example, based on relative cumulative function:
If the random number was less than 0.05, our distribution-based random number is 1.5
If the random number was between 0.05 and 0.55, our distribution-based random number is 2,
If was more than 0.55, our distribution-based random number is 4
We should do a similar work with continuous distribution functions. The difference is that in continuous world, we use integral instead of cumulative function. So for your question, we have:
f(x)=cos(x) , 0<=x<=90
F(x)=sin(x)-sin(0)=sin(x) , 0<=x<=90
F'(x)=cos(x) , 0<=x<=90 (Because F(90)=1)
Now we generate a random number between 0 and 1 (like r). So we have:
F'(x)=r => sin(x)=r => x=arcsin(r)
Actually, you just need to generate a random number between 0 and 1 and calculate the arcsin of that.
What I'm trying to accomplish is the following:
I wish to create a vector of integers, from a relatively small range, and ensure that none of the integers will be followed by the same integer.
i.e., This is a "legal" vector:
[ 1 3 4 2 5 3 2 3 5 4 ]
and this is an "illegal" vector (since 5 follows 5):
[ 1 3 4 2 5 5 2 3 5 4 ]
I've experimented with randi, and all sorts of variations with randperm, and I always get stuck when i try to generate a vector of around 100 elements, from a small range (i.e., integers between 1 and 5).
The function just runs for too long.
Here's one of the attempts that i've made:
function result = nonRepeatingRand(top, count)
result = randi(top, 1, count);
while any(diff(result) == 0)
result = randi(top, 1, count);
end
end
Any and all help will be much appreciated. Thanks !
The kind of sequence you are looking for can be defined by generating differences from 1 to top - 1 and then computing the cumulative sum modulus top, starting from a random initial value:
function result = nonRepeatingRand(top, count)
diff = randi(top - 1, 1, count);
result = rem(cumsum(diff) + randi(1, 1, count) - 1, top) + 1;
end
On my machine, this generates a non-repeating sequence of 10 million numbers out of 1:5 in 0.58 seconds.
you can use the following code for generate Non Repeating Random Numbers from 1 to M
randperm(M);
and for K Non Repeating Random Numbers from 1 to M
randperm(M, K);
enjoy
Do not regenerate the sequence every time, but fix the repetitions. E.g.:
function result = nonRepeatingRand(top, count)
result = randi(top, 1, count);
ind = (diff(result) == 0);
while any(ind)
result(ind) = [];
result(end + 1 : count) = randi(top, 1, count - numel(result));
ind = (diff(result) == 0);
end
end
On my machine, this generates a non-repeating sequence of 10 million numbers out of 1:5 in 1.6 seconds.
Taking the idea from A. Donda but fixing the implementation:
r=[randi(top,1,1),randi(top - 1, 1, count-1)];
d=rem(cumsum(r)-1,top)+1;
The first element of r is a randomly chosen element to start with. The following elements of r randomly choose the difference to the previous element, using modulo arithmetic.
How this?
top = 5;
count = 100;
n1 = nan;
out = [];
for t = 1: count
n2 = randi(top);
while n1 == n2
n2 = randi(top);
end
out = [out, n2];
n1 = n2;
end
Say that I have a dataset:
Jday = datenum('2009-01-01 00:00','yyyy-mm-dd HH:MM'):1/24:...
datenum('2009-01-05 23:00','yyyy-mm-dd HH:MM');
DateV = datevec(Jday);
DateV(4,:) = [];
DateV(15,:) = [];
DateV(95,:) = [];
Dat = rand(length(Jday),1)
How is it possible to remove all of the days that have less than 24 measurements. For example, in the first day there is only 23 measurements thus I would need to remove that entire day, how could I repeat this for all of the array?
A quick solution is to group by year, month, day with unique(), then count observation per day with accumarray() and exclude those with less than 24 obs with two steps of logical indexing:
% Count observations per day
[unDate,~,subs] = unique(DateV(:,1:3),'rows');
counts = [unDate accumarray(subs,1)]
counts =
2009 1 1 22
2009 1 2 24
2009 1 3 24
2009 1 4 24
2009 1 5 23
Then, apply criteria to the counts and retrieve logical index
% index only those that meet criteria
idxC = counts(:,end) == 24
idxC =
0
1
1
1
0
% keep those which meet criteria (optional, for visual inspection)
counts(idxC,:)
ans =
2009 1 2 24
2009 1 3 24
2009 1 4 24
Finally, find the members of Dat that fall into the selected counts with a second round of logical indexinf through ismember():
idxDat = ismember(subs,find(idxC))
Dat(idxDat,:)
Rather long answer, but I think it should be useful. I would do this using containers.Map. Possibly there is a faster way, but maybe for now this one will be good.
Jday = datenum('2009-01-01 00:00','yyyy-mm-dd HH:MM'):1/24:...
datenum('2009-01-05 23:00','yyyy-mm-dd HH:MM');
DateV = datevec(Jday);
DateV(4,:) = [];
DateV(15,:) = [];
DateV(95,:) = [];
% create a map
dateMap = containers.Map();
% count measurements in each date (i.e. first three columns of DateV)
for rowi = 1:1:size(DateV,1)
dateRow = DateV(rowi, :);
dateStr = num2str(dateRow(1:3));
if ~isKey(dateMap, dateStr)
% initialize Map for a given date with 1 measurement (i.e. our
% counter of measuremnts
dateMap(dateStr) = 1;
continue;
end
% increment measurement counter for given date
dateMap(dateStr) = dateMap(dateStr) + 1;
end
% get the dates
dateStrSet = keys(dateMap);
for keyi = 1:numel(dateStrSet)
dateStrCell = dateStrSet(keyi);
dateStr = dateStrCell{1};
% get number of measurements in a given date
numOfmeasurements = dateMap(dateStr);
% if less then 24 do something about it, e.g. save the date
% for later removal from DateV
if numOfmeasurements < 24
fprintf(1, 'This date has less than 24 measurement: %s\n', dateStr);
end
end
The results is:
This date has less than 24 measurement: 2009 1 1
This date has less than 24 measurement: 2009 1 5