Кажется, что Mathworks имеет специальные квадраты с ячейками в своей функции власти (к сожалению, это все встроенный закрытый источник, который мы не можем видеть). В моем тестировании на R2013b кажется, что .^
, power
и realpow
используют тот же алгоритм. Для квадратов я считаю, что они имеют специальную оболочку x.*x
.
1.0x (4.4ms): @()x.^2
1.0x (4.4ms): @()power(x,2)
1.0x (4.5ms): @()x.*x
1.0x (4.5ms): @()realpow(x,2)
6.1x (27.1ms): @()exp(2*log(x))
Для кубов история отличается. Они больше не являются специальными. Опять же, .^
, power
и realpow
все похожи, но гораздо медленнее, на этот раз:
1.0x (4.5ms): @()x.*x.*x
1.0x (4.6ms): @()x.*x.^2
5.9x (26.9ms): @()exp(3*log(x))
13.8x (62.3ms): @()power(x,3)
14.0x (63.2ms): @()x.^3
14.1x (63.7ms): @()realpow(x,3)
Давайте прыгать до 16 власти, чтобы увидеть, как эти алгоритмы масштаба:
1.0x (8.1ms): @()x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x
2.2x (17.4ms): @()x.^2.^2.^2.^2
3.5x (27.9ms): @()exp(16*log(x))
7.9x (63.8ms): @()power(x,16)
7.9x (63.9ms): @()realpow(x,16)
8.3x (66.9ms): @()x.^16
Итак: .^
, power
и realpow
все работают в течение постоянного времени относительно экспоненты, если только это не было специальным корпусом (-1 тоже, по-видимому, было специально обложено). Использование трюка exp(n*log(x))
также является постоянным временем относительно экспоненты и быстрее. Единственный результат я не совсем понимаю, почему повторное квадратирование медленнее, чем умножение.
Как и ожидалось, увеличение размера x
в 100 раз увеличивает время аналогично для всех алгоритмов.
Итак, мораль истории? При использовании скалярных целых показателей всегда выполняйте умножение самостоятельно. В power
много друзей, и друзья (экспоненты могут быть плавающей точкой, вектором и т. Д.). Единственные исключения - это то, где Mathworks выполнила оптимизацию для вас. В 2013b, кажется, x^2
и x^(-1)
. Надеюсь, они со временем добавят больше. Но, в целом, возведение в степень трудно и умножение легко. В коде, чувствительном к производительности, я не думаю, что вы можете ошибаться, всегда печатая x.*x.*x.*x
. (Конечно, в вашем случае, следуйте советам Luis` и использовать промежуточные результаты в каждом члене!)
function powerTest(x)
f{1} = @() x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x;
f{2} = @() x.^2.^2.^2.^2;
f{3} = @() exp(16.*log(x));
f{4} = @() x.^16;
f{5} = @() power(x,16);
f{6} = @() realpow(x,16);
for i = 1:length(f)
t(i) = timeit(f{i});
end
[t,idxs] = sort(t);
fcns = f(idxs);
for i = 1:length(fcns)
fprintf('%.1fx (%.1fms):\t%s\n',t(i)/t(1),t(i)*1e3,func2str(fcns{i}));
end
оптимизация, которая предположительно сделана на 'х. * Х. * Х. * X' ведет себя странно. Я пробовал «x. *. X. * .... * X' с переменным числом« x »от 2 до 8, а время более или менее линейно возрастает. Я бы ожидал ударов; например, случай «8» (=> 'x.^2.^2.^2': три силовых операции) должен занимать меньше времени, чем« 7 »(=> больше операций с энергией) –
@LuisMendo Я не знаю как проверить, но я мог представить, что он делает только 1 шаг (без вложенной оптимизации). Для 7 оно затем сводится к чему-то вроде: «x.^2 * x.^2 * x.^2. * x', который не будет медленнее, чем' x.^2 * x.^2 * x.^2 . * x.^2' for 8. Если бы 8 выполнялось быстрее, чем 7, таким образом, Mathworks, вероятно, вложил бы такую оптимизацию в силовую функцию. –
Да, это может быть объяснение: нет гнездования –