简体   繁体   中英

What can I do to make this code shorter?

I want to compute this function for more k , like k = 6,7,8... etc:

f(k,a) = (-1) k a-(-1) k (kπ/t) 2

Then I want to plot it for all k 's. I just want it in shorter form. I have tried to write k as a vector but that doesn't work. Here is my code:

clear all
close all
clc
w = linspace(-1,10,5000);
t = 2*pi;

k = 0;
a0 = w.^2;
b0 = (-1).^k.*a0-((-1).^k).*(k*pi/t).^2;
b = a0*0;
k1 = 1;
a01 = w.^2;
b01 = (-1).^k1.*a01-((-1).^k1).*(k1*pi/t).^2;

k2 = 2;
a02 = w.^2;
b02 = (-1).^k2.*a02-((-1).^k2).*(k2*pi/t).^2;

k3 = 3;
a03 = w.^2;
b03 = (-1).^k3.*a03-((-1).^k3).*(k3*pi/t).^2;

k4 = 4;
a04 = w.^2;
b04 = (-1).^k4.*a04-((-1).^k4).*(k4*pi/t).^2;

k5 = 5;
a05 = w.^2;
b05 = (-1).^k5.*a05-((-1).^k5).*(k5*pi/t).^2;

plot(a0,b,'.')
hold on
plot(a0,b0,'.')
hold on
grid on
plot(a01,b01,'.')

tl;dr - Here is both compact and vectorized way:

t = 2*pi;
myfun = @(k,a) (-1).^k.*a-((-1).^k).*(k*pi/t).^2;
k = 0:30; % here you can add as many k's you like
w = linspace(-1,10,5000).^2.';
b0 = zeros(size(w));
B = bsxfun(myfun,k,w);
plot(w,[b0 B],'.')
grid on

the result:

在此处输入图片说明

Explanations:

Your code demonstrates how you should not use a variable. If a01==a02==a03... then you could just use a for all of them, no need to define all those a 's. The same holds for the function b0 , b01 and so on, you can define an anonymous function (the shortest type of functions) that do that, and call it over and over. If you just do this 2 things your code above (without plotting) becomes:

w = linspace(-1,10,5000);
t = 2*pi;
b_fun = @(k,a) (-1).^k.*a-((-1).^k).*(k*pi/t).^2;
a = w.^2;
k = 0;
b0 = b_fun(k,a);
b = a*0;
k1 = 1;
b01 = b_fun(k1,a);
k2=2;
b02 = b_fun(k2,a);
k3=3;
b03 = b_fun(k3,a);
k4 = 4;
b04 = b_fun(k4,a);
k5 = 5;
b05 = b_fun(k5,a);

Which is shorter and much more readable. Note, that we define t before the function, so it's calculated by it's values within the function.

Next, you can use singleton expansion to compute all pairwise combinations of elements from a and your k 's in one command (and in a vectorized way):

k = 0:5
B = bsxfun(b_fun,k,a.');

This creates a matrix where each column is all the resulted values for b_fun(k(i),a) . The first input to bsxfun is any element-wise binary operation, like our function b_fun . Next there are always 2 arrays (one of them can be scalar), the first holds all the values for the first argument in our function, and the second is for the second argument. If one of the arrays have a singleton dimension where the other is larger than one, than bsxfun expands the smaller one to fit the larger one. In our case k is singleton in rows, and a is singleton in columns, so the result has the no. of columns from k , and the no. of rows from a .

So up to here we got:

w = linspace(-1,10,5000);
t = 2*pi;
b_fun = @(k,a) (-1).^k.*a-((-1).^k).*(k*pi/t).^2;
a = w.^2;
k = 0:5;
B = bsxfun(b_fun,k,a.');
b = a*0;

We can go further and remove some duplicated variables - use w.^2 instead of a , and replace the constant pi/t by 0.5 . Also it's more clear to write b = zeros(size(w)) , instead of a*0 :

w = linspace(-1,10,5000).';
b_fun = @(k,a) (-1).^k.*a-((-1).^k).*(k*0.5).^2;
k = 0:5;
B = bsxfun(b_fun,k,w.^2);
b = zeros(size(w));

Now for the plotting. plot can take several series of data in columns of one matrix, and display all of them against the same variable, so we can use our B directly, and just concat to it b :

plot(w.^2,[b B],'.')

You could benefit from the definition of function in programming. Something like this can be done:

function main
w=linspace(-1,10,5000);
t=2*pi;

figure;hold on
for k=0:5
    [a,b] = getNext(k,w,t);
    plot(a,b,'.');
end

function [a,b] = getNext(k,w,t)
a = w.^2;
b = (-1).^k.*a-((-1).^k).*(k*pi/t).^2;
end
end 

Remember that this is not the only solution. Other ways to get similar result are possible too.

Update A built-in for-loop using arrayfun is like this:

w = linspace(-1,10,5000);
t = 2*pi;
a = w.^2;
K = [0 1 2 3 4 5 6 7];
S = arrayfun(@(k)((-1).^k.*a-((-1).^k).*(k*pi/t).^2),K,'UniformOutput',false);
figure;hold on
for ii=1:numel(K)
    plot(a,S{ii},'.');
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM