Есть много вещей, которые вы можете сделать, чтобы ускорить вычисления.Одним из важных является удаление циклов и замена их векторизованным кодом.Octave работает намного быстрее, когда выполняет много вычислений по одному, а не по одному за раз.
Например, вместо
for l = 1:N
for s = 1:N
if(((l-x).*cos(w.*pi)+(s-y).*sin(w.*pi)).^2/a.^2 + (-(l-x).*sin(w.*pi) + (s-y).*cos(w.*pi)).^2/b.^2 <= 1)
f(l,s) = cos(0.001)+i.*sin(0.001);
end
end
end
можно написать
l = 1:N;
s = (1:N).';
index = ((l-x).*cos(w.*pi)+(s-y).*sin(w.*pi)).^2/a.^2 + (-(l-x).*sin(w.*pi) + (s-y).*cos(w.*pi)).^2/b.^2 <= 1;
f(index) = cos(0.001)+i.*sin(0.001);
Однако здесь мы все еще выполняем слишком много работы, потому что мы вычисляем index
в тех местах, которые, как мы знаем, находятся за пределами эллипса.В идеале мы бы нашли меньшую область вокруг каждой точки (x,y)
, в которую, как мы знаем, эллипс вписывается.
Еще одна важная вещь, которую нужно сделать, - это предварительно выделить массив.f
растет внутри итераций цикла.Вместо этого нужно создать f
с его окончательным размером до начала цикла.
Также выполняется много избыточных вычислений.Например, w.*pi
вычисляется несколько раз, и cos
и sin
тоже.Вы также назначаете cos(0.001)+i.*sin(0.001)
для вывода пикселей снова и снова, это может быть константа, вычисляемая один раз.
Следующий код запускается в MATLAB за доли секунды (хотя Octave будет намного медленнее),Я также правильно разделил N
и M
(поэтому выходные данные не всегда квадратные) и сделал размеры шагов переменными для лучшего понимания кода.Я присваиваю 1
элементам эллипса, вы можете заменить их своей константой, умножив f = f * (cos(0.001)+i*sin(0.001))
.
N = 150;
M = 200;
a = 5;
b = 10;
x_step = 25;
y_step = 25;
f = zeros(N,M);
for x = x_step/2:x_step:M
for y = y_step/2:y_step:N
phi = rand(1)*pi;
cosphi = cos(phi);
sinphi = sin(phi);
l = (1:M)-x;
s = (1:N).'-y;
index = (l*cosphi+s*sinphi).^2/a.^2 + (-l*sinphi + s*cosphi).^2/b.^2 <= 1;
f(index) = 1;
end
end