I want to split an array into segments by percents. For example, divide 100 elements into segments occupying [1/3,1/4,5/12], but [1/3,1/4,5/12]*100=[33.3,25,41.7], so it's necessary to adjust them to integers [33,25,42] (others like [34,24,42] or [33,26,41] are also acceptable, a wandering within 1 is not important).
Currently I use a loop to do this recursively
function x = segment(n,pct)
x = n * pct;
y = fix(x);
r = x - y;
for ii = 1 : length(r)-1
[r(ii),r(ii+1)] = deal(fix(r(ii)),r(ii+1)+r(ii)-fix(r(ii)));
end
x = y + r;
segment(100,[1/3,1/4,5/12]) gives [33,25,42].
Is there better way without recursive loop?
You can just use Adiel's comment for most of the cases, and just catch any rogue result after and correct it, only if it needs to be corrected:
function out = segmt( n , pct )
% This works by itself in many cases
out = round(n.*pct) ;
% for the other cases:
% if the total is not equal to the initial number of point, the
% difference will be affected to the largest value (to minimize the
% percentage imbalance).
delta = sum(out) - n ;
if delta ~= 0
[~,idx] = max( out ) ;
out(idx) = out(idx) - delta ;
end
Related
I want to plot the log of a variable Dl which depends on a variable z with respect to log(z). I'm trying to do this for z = 1:100 but it returns only 1 number for Dl.
% Log(Dl) versus Log(Redshift)
m = 1;
d = 0;
z = linspace(1,100,1);
Dl = zeros(1,100);
for z = 1:100
[Dl,Da] = Cosmological(m,d,z);
end
y = log(Dl);
x = log(1:100);
plot(x,y)
apologies for any silly or useless lines of code I'm very new to programming. The function cosmological that I called for is written as follows (but there are no errors so may not be necessary, I'm posting just in case):
function [Dl,Da] = Cosmological(m,d,z)
f = #(x)1./((1+x).*((m.*(1+z)-m+d.*((1+x).^(-2))-d+1).^(.5)));
q = integral(f,0,z); % Integral part equations for Dl
if m+d==1 % flat universe condition
Dl=c/H0.*(1+z)*q;
elseif m+d<1 %positive spatial curvature universe condition
Dl=c/H0*(1-m-d)^(-1/2)*(1+z)*sinh((1-m-d)^.5).*q;
else % negative spatial curvature universe condition
Dl=c/H0*(1-m-d)^(-1/2)*(1+z)*sin((1-m-d)^.5).*q;
end
Da = Dl/(1+z)^2; %Angular diameter distance function
end
First, these line is not needed, you assign z with 1:100 in the loop:
z = linspace(1,100,1);
You get only one value because your loop saves only the last value. You should index Dl with z like this (and probably also Da):
for z = 1:100
[Dl(z),Da] = Cosmological(m,d,z);
end
I have an 80x1 cell array, where each cell element has a different size. I want to round the second and third columns of each cell to the closest integer, divided by 4. I have no idea hoe to do it. I have tried cellfun so far but it didint work. See below for my code:
clear all;
clc;
for k = 1 : 80
A{k} = 1 : k;
end
for k = 1 : 80
B{k} = 1 : k;
end
for k = 1 : 80
newb{k} = 1 : k;
end
for k = 1 : 80
r5{k} = 1 : k;
% code to create Mcell i.e cell array 400 x 1
Mcell = mat2cell(a5n,repmat(174,400,1),3)
%each image size x and y
for ii=1:80 [A{ii,1},B{ii,1}] =find(Mcell{ii,1} == 280);
% ii
%find sizes 13 and their locations in Mcell(ii,1)
newb{ii,1}=Mcell{ii,1}(A{ii,1},:);
%ii matrix with size and locations x y. i.e size=13 x=4 y=50
end
cellfun(#round,newbii,1}(:,2:3)/4)*4);
newb{ii,1}=Mcell{ii,1}(A{ii,1},:);
This should do your thing:
cellfun(#(x)(round(x(:,[2:3])/4)), C, 'UniformOutput', false)
In response to your code, for a start you don't need so many for loops!
Do one 1:80 loop containing all the similar lines...
for k = 1:80
A{k} = 1 : k;
B{k} = 1 : k;
newB{k} = 1 : k;
r5{k} = 1 : k;
% code to create Mcell i.e cell array 400 x 1
Mcell = mat2cell(a5n,repmat(174,400,1),3)
% Not sure what your further lines are trying to achieve
% so I have stopped copying code here...
end
In answer to your actual question, to "round the values in the second and third columns to the nearest integer divided by 4"...
Be aware that if you're talking about the Cells A, B, etc. then note that some of these don't have two or three columns as your loop goes from 1 so the first entry only has 1 column?
But your initial code aside, you should be able to do the following with an 80x1 Cell called myCell:
for i = 1:80
% Access myCell{Row}(Column)
% Where myCell contains 80 row vectors
myCell{i}(2) = round(myCell{i}(2)) / 4;
myCell{i}(3) = round(myCell{i}(3)) / 4;
end
It is unclear whether you mean to round before or after the division by 4. The above code rounds first, if you want to round after then of course instead use
myCell{i}(3) = round(myCell{i}(3) / 4 );
I am just jumping back into R after a long time away and I am surprised by how simple some of the things are to do. I have created 3 arrays:
Xs = runif(N, min=-1, max=1);
Ys = runif(N, min=-1, max=1);
Rs = sqrt( Xs^2 + Ys^2 );
where, obviously, X and Y (together) define N points within the (-1,1) square and R is the vector defining the distances of these points.
If I want to count the number of elements in Rs which are less than or equal to 1, is there a simple inl-line command to do this?
sum( Rs <= 1 )
Rs <= 1 yields a logical vector. TRUE equals 1; FALSE equals 0.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I need to simulate an information source with alphabet "a,b,c,d" with the respective probabilities of 0.1, 0.5, 0.2, 0.2. I do not know how to do it using MATLAB. Help is most appreciated.
You could first create an array containing the relative numbers of each character defined by their relative probabilities.
First set the max # of samples for any letter; doesn't have to be the same as the # of rand samples (later below):
maxSamplesEach = 100;
Define the data for the problem:
strings = ['a' 'b' 'c' 'd'];
probabilty = [0.1 0.5 0.2 0.2];
Construct a sample space weighted by relative probabilities:
count = 0;
for k = 1:size(strings,2)
for i = 1:probabilty(k)*maxSamplesEach
count = count+1;
totalSampleSpace(count) = strings(k);
end
end
Now define a range for the random numbers:
min = 1;
max = count;
Now generate a 100 random numbers from a uniform distribution from the range defined above:
N = 100;
randomSelections = round(min + (max-min).*rand(1,N));
Now here are your random samples taken from the distribution:
randomSamples = totalSampleSpace(randomSelections);
Next just count them up:
for k = 1:size(strings,2)
indices = [];
indices = find(randomSamples == strings(k));
disp(['Count samples for ', strings(k),' = ', num2str(size(indices,2))]);
end
Keep in mind that these results are statistical in nature so its highly unlikely that you will get the same relative contributions each time.
Example output:
Count samples for a = 11
Count samples for b = 49
Count samples for c = 19
Count samples for d = 21
you could do something as simple as follows. Simply create a large random vector using rand, this will create values between 0 and 1 with a uniform probability. So if you want a number to have a 10 percent chance of occurring you give it a range of 0.1, typically 0 to 0.1. You can then add more ranges to these same numbers to get what you want.
vals =rand(1,10000);
letters = cell(size(vals));
[letters{vals<0.1}] = deal ('a');
[letters{vals > 0.1 & vals <= 0.6}] = deal ('b');
[letters{vals > 0.6 & vals <= 0.8}] = deal ('c');
[letters{vals > 0.8 & vals <= 1}] = deal ('d');
The above code will return a 10000 character letter array with the described percentages.
Or you can do this dynamically as follows:
vals =rand(1,10000);
output= cell(size(vals));
letters2use = {'a','b','c','d'};
percentages = [0.1,0.5,0.2,0.2];
lowerBounds = [0,cumsum(percentages(1:end-1))];
upperBounds = cumsum(percentages);
for i = 1:numel(percentages)
[output{vals > lowerBounds(i) & vals <= upperBounds(i)}] = deal(letters2use{i}) ;
end
UPDATE
The above code has no guarantee of a certain number of occurrences of each letter, however the following does. Since from your comment it seems you need exactly a certain number of each the following code should do that by randomly assigning letters around
numElements = 10000;
letters2use = {'a','b','c','d'};
percentages = [0.1,0.5,0.2,0.2];
numEach = round(percentages*numElements);
while sum(numEach) < numElements
[~,idx] = max(mod(percentages*numElements,1));
numEach(idx) = numEach(idx) + 1;
end
while sum(numEach) > numElements
[~,idx] = min(mod(percentages*numElements,1));
numEach(idx) = numEach(idx) - 1;
end
indices = randperm(numElements);
output = cell(size(indices));
lower = [0,cumsum(numEach(1:end-1))]+1;
upper = cumsum(numEach);
for i = 1:numel(lower)
[output{indices(lower(i):upper(i))}] = deal(letters2use{i});
end
output
int foo(int n)
{
int x=2;
while (x<n)
{
x = x*x*x;
}
return x;
}
I need to analyze its time complexity. I noticed it reaches n much faster than just log(n). I mean, it does less steps than O(log(n)) would do. I read the answer but have no idea how they got to it: It is O(log(log(n)). Now, how do you approach such a question?
think of it as a recursive function:
f(i) = f(i-1)^3
if you expand it:
f(i) = ((f(i-k)^3)^3)[...k times] = f(i-k)^(3^k) = f(0)^(3^i)
the function grows as the power of the power... so the time (iterations) to reach a certain number (that is, calculating the inverse of the function) is the logarithm of the logarithm.
As in your example f(0) = 2, we want to know when f(i) >= n being n the input parameter (and i the number of iterations):
f(i) = 2^(3^i) >= n
3^i >= log_2(n)
i >= log_3(log_2(n))
So to reach a value of n, it takes log_3(log_2(n)) iterations (round up while dealing with integers to surpass it).
if the function would be:
f(i) = 2*f(i-1) //e.g. x=2*x
then the pattern would be:
f(i) = 2*2*[...k times]*f(i-k) = f(i-k)*(2^k) = f(0)*(2^i)
And in this case, then the inverse of the function would be a single logarithm in base 2.
My math is not very rigorous, but I hope you'll get the idea.
Think about how x changes with the number of iterations through the loop. Each time, you cube it. So after i iterations, the value will be 2 cubed, cubed again... and so on, i times. Let's use x(i) to denote this expression. Let's say x(0)=2, x(1)=23, etc (I'm using ab to mean a raised to the bth power).
We're done when x(i)>=n. How long does it take? Let's solve for i.
First, we take a log on both sides: ln(x(i))>=ln(n)
ln(x(i)) = ln(x(i-1))*3 = ln(x(i-2))*(3**2) = ... = ln(x(0))*(3**i)
(the above uses [this property][1]: ln(x**b)==ln(x)*b)
so, 3**i * 2 >=ln(n). Let's take another logarithm:
ln(3**i * 2) = ln(2) + ln(3)*i
so ln(2) + ln(3)* i >= ln(ln(n))
Now we can solve for i: i >= ( ln(ln(n))-ln(2) ) / ln(3)
We can ignore the constant factors, and we're left with the conclusion that we'll take log(log(n)) steps. That's the complexity of your algorithm.
Hopefully, breaking down all the steps like that helps.
Let
L3 = log to the base 3
L2 = Log to the base 2
Then the correct answer is O(L3(L2(n)) and NOT O(L2(L2(n)).
Start with x = x * 2. x will increase exponentially till it reaches n, thus making the time complexity O(L2(n))
Now consider x = x * x. x increases faster than the above. In every iteration the value of x jumps to the square of its previous value. Doing some simple math, here is what we get:
For x = 2
n = 4, iterations taken = 1
n = 16, iterations taken = 2
n = 256, iterations taken = 3
n = 65536, iterations taken = 4
Thus, the time complexity is O(L2(L2(n)). You can verify this by putting values above values for n.
Now coming to your problem, x = x * x * x. This will increase even faster than x = x * x. Here is the table:
For x = 2
n = 8, iterations taken = 1
n = 512, iterations taken = 2
n = (512*512*512), iterations taken = 3 and so on
If you look at this carefully, this turns out to be O(L3(L2(n)). L2(n) will get you the power of two, but since you are taking cube of x in every iteration, you will have to take log to the base 3 of it to find out the correct number of iteration taken.
So I think the correct answer is O(log-to-base-3(log-to-base-2(n))
Generalizing this, if x = x * x * x * x * .. (k times), then the time complexity is O(log-to-base-k(log-to-base-2(n)
If the code inside the while loop were
x = 2*x;
x would reach n in O(log(n)) iterations. Since you're cubing x instead of just multiplying it by a constant, you'll reach n faster.
Given
log ( A * x ) == log ( A ) + log ( x )
log ( x * x * x ) == 3 * log ( x )
So
log ( log ( x * x * x ) ) == log ( 3 * log ( x ) )
== log ( 3 ) + log ( log ( x ) )
How much faster or slower ( measured by number of iterations of the loop ) will this function be than your function?
int log_foo ( int n )
{
double log_x = log ( 2 );
const double log_n = log ( n );
while ( log_x < log_n )
{
log_x = 3 * log_x;
}
return exp ( log_x );
}
And how much faster or slower will this function be than your function?
int log_log_foo ( int n )
{
double log_log_x = log ( log ( 2 ) );
const double log_log_n = log ( log ( n ) );
const double log_3 = log ( 3 );
while ( log_log_x < log_log_n )
{
log_log_x += log_3;
}
return exp ( exp ( log_log_x ) );
}
But this function only increments log_log_x by a constant, so it's easy to work out how many iterations it does.
Let i be the number of iteration steps and x(i) the value of x after i steps. We have
x(0) = 2
x(i) = x(i-1)³
The total number of steps is the biggest i so that x(i) < n.
We have
log x(i) = log x(i-1)³
= 3·log x(i-1)
= 3·log x(i-2)³
= 3²·log x(i-2)
= 3^i·log x(0)
= 3^i·log 2
⇒ log log x(i) = log (3^i·log 2)
= log 3^i + log log 2
= i·log 3 + log log 2
The logarithm is strictly increasing, so
x(i) < n ⇔ log log x(i) < log log n
⇔ i·log 3 + log log 2 < log log n
⇔ i < (log log n - log log 2) / log 3 ∈ O(log log n)
Why not add a counter variable to count the number of iterations of the loop. Print it out just before the function returns.
Then call the function for a range of values, e.g. 3 to 1,000,000 to start with. Then plot your result using something like GNUPlot.
Then see if the graph matches a known curve.