sha*_*ant 6 performance matlab anonymous-function
假设你有一个50000次迭代的循环,并希望从很多矩阵中计算平均值(标量).这不完整,但大致如下:
for k=1:50000
...
mean=sum(sum(matrix))/numel(matrix); %Arithmetic mean
...
end
Run Code Online (Sandbox Code Playgroud)
现在想要包括不同的均值方程式可供选择.首先我尝试了这个:
average='arithmetic'
for k=1:50000
...
switch average
case 'arithmetic'
mean=sum(sum(matrix))/numel(matrix); %Arithmetic mean
case 'geometric'
mean=prod(prod(matrix)).^(1/numel(matrix)); %Geometric mean
case 'harmonic'
mean=numel(matrix)/sum(sum(1./matrix)); %Harmonic mean
end
...
end
Run Code Online (Sandbox Code Playgroud)
这显然比第一个循环慢很多,因为它需要为每次迭代找到匹配的字符串,感觉真的没必要.然后我尝试了这个:
average='arithmetic'
switch average
case 'arithmetic'
eq=@(arg)sum(sum(arg))/numel(arg); %Arithmetic mean
case 'geometric'
eq=@(arg)prod(prod(arg)).^(1/numel(arg)); %Geometric mean
case 'harmonic'
eq=@(arg)numel(arg)/sum(sum(1./arg)); %Harmonic mean
end
for k=1:50000
...
mean=eq(matrix); %Call mean equation
...
end
Run Code Online (Sandbox Code Playgroud)
这仍然是第一个循环的两倍慢,我不明白为什么.最后两个循环的速度几乎相似.
我在这里做错了吗?如何通过这个额外功能实现与第一个循环相同的性能?
非常感谢帮助!
小智 5
将开关置于循环内是执行50000次比较,只需要执行一次,这是我建议的.
第二个是更微妙的,但很有可能每次迭代都会动态查找eq函数,并且每次都可能解释(不确定MATLAB如何进行优化).性能最好的选择可能是将for循环放在开关内部
switch average
case 'arithmetic'
for ... end
case 'geometric'
for ... end
case 'harmonic'
for ... end
end
Run Code Online (Sandbox Code Playgroud)
好吧,每个函数,甚至是匿名函数,都可以预期在调用它时会产生一些额外的开销,使它们比你的例子中的单行表达式稍慢一些.但是,在这种情况下,可能会有额外的开销,因为名称中的函数eq已经在MATLAB中大量存在,因为它eq是重载==运算符的方法名称.像这样使用WHICH命令:
>> which eq -all
Run Code Online (Sandbox Code Playgroud)
会告诉你,eq是严重超载,与一个现有的每个基本数据类型和最对象.
我会尝试使用不同的名称作为你的匿名函数句柄,看看调度是否可能是一个因素,虽然我有点怀疑它是基于函数优先顺序(即变量总是看起来优先).性能方面的最佳解决方案可能是通过执行类似DavW建议的操作来避免额外的函数调用开销.
我想提出另一个建议.您正在进行的许多数学运算可以大大提高,以提高它们的效率,特别是通过使用函数MEAN和冒号运算符将整个矩阵重新整形为列向量:
result = mean(matrix(:)); %# For the arithmetic mean
result = prod(matrix(:))^(1/numel(matrix)); %# For the geometric mean
result = 1/mean(1./matrix(:)); %# For the harmonic mean
Run Code Online (Sandbox Code Playgroud)
请注意,我没有使用mean我的变量的名称,因为它已经用于内置函数,你绝对不想暗示它.
| 归档时间: |
|
| 查看次数: |
740 次 |
| 最近记录: |