2014-02-04 4 views
2

Я пытаюсь улучшить скорость сценария, который я пытаюсь запустить.Preallocation и Vectorization Speedup

Вот код: (моя машина = 4 ядра выигрыш 7)

clear y; 
n=100; 
x=linspace(0,1,n); 
% no y pre-allocation using zeros 
start_time=tic; 

for k=1:n, 
    y(k) = (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60))/(1+(2/5)*x(k)-(1/20)*x(k)^2); 
end 

elapsed_time1 = toc(start_time); 
fprintf('Computational time for serialized solution: %f\n',elapsed_time1); 

Приведенный выше код дает 0.013654 истекшее время.

С другой стороны, я попытался использовать предварительное выделение, добавив y = zeros(1,n); в приведенном выше коде, где комментарий есть, но время работы примерно равно ~ 0,01. Любые идеи почему? Мне сказали, что это улучшится в 2 раза. Я что-то упустил?

Наконец, есть ли какой-либо тип векторизации в Matlab, который позволит мне забыть о цикле for в приведенном выше коде?

Спасибо,

+1

Попробуйте с n = 1000000; Вы должны увидеть разницу. 100 слишком мал. – grantnz

ответ

3

В коде: попробуйте n=10000 и вы увидите больше разница (фактор почти 10 на моей машине).

Эти вещи, связанные с распределением, наиболее заметны, когда размер вашей переменной большой. В этом случае Matlab сложнее динамически распределять память для этой переменной.


Чтобы уменьшить количество операций: сделать это векторизация и повторное использование промежуточных результатов, чтобы избежать полномочий:

y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20)); 

Бенчмаркинг:

С n=100:

Параг-х/раствор venergiac:

>> tic 
for count = 1:100 
y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2); 
end 
toc 
Elapsed time is 0.010769 seconds. 

Мое решение:

>> tic 
for count = 1:100 
y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20)); 
end 
toc 
Elapsed time is 0.006186 seconds. 
+0

Действительно? Я не вижу более чем 2x улучшения скорости с n = 1000000. – grantnz

+0

Отличный трюк! –

+1

@Parag Спасибо! Я снова использовал трюк из [здесь] (http://stackoverflow.com/questions/18993590/efficient-way-to-take-powers-of-a-vector), на самом деле –

2

Вам не нужен for цикл. Замените петлю for следующим образом, и MATLAB обработает ее.

y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2); 

Это может дать вычислительное преимущество, когда векторы становятся больше по размеру. Меньший размер - причина, по которой вы не видите эффект предварительного распределения. Прочтите страницу this для получения дополнительных советов о том, как повысить производительность.

Edit: я заметил, что при больших размерах, n>=10^6, я получаю постоянное улучшение производительности при попытке следующее:

x=0:1/n:1; 

вместо использования linspace. При n=10^7 я получаю 0,05 секунды (0,03 против 0,08), НЕ используя linspace.

+0

интересная страница – venergiac

+1

Количество операций (и прошедшее время) может быть уменьшено путем повторного использования промежуточных результатов, чтобы избежать полномочий; см. мой ответ. –

+0

@ LuisMendo Я провел тест с вашим и моим кодом для n = 100000, и я получил 10-кратное улучшение (1.132 против 0.155). Мне действительно удивительно, что ручная факторизация делает такую ​​большую разницу. –

1

операция попытки элемент на элемент (.*, .^)

clear y; 
n=50000; 
x=linspace(0,1,n); 
% no y pre-allocation using zeros 
start_time=tic; 

for k=1:n, 
    y(k) = (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60))/(1+(2/5)*x(k)-(1/20)*x(k)^2); 
end 

elapsed_time1 = toc(start_time); 
fprintf('Computational time for serialized solution: %f\n',elapsed_time1); 

start_time=tic; 
y = (1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))/(1+(2/5)*x-(1/20)*x.^2); 

elapsed_time1 = toc(start_time); 
fprintf('Computational time for product solution: %f\n',elapsed_time1); 

моей данные

Вычислительный время для сериализованного решения: 2,578290

Вычислительного время для сериализованного решения: 0,010060