对于一个非常好的第一近似,向量化的目标是避免循环并使用整个数组操作的towrite代码。作为心房的例子,考虑
for i = 1:n for j = 1:m c(i,j) = a(i,j) + b(i,j); endfor endfor
与简单得多的相比
c = a + b;
这不仅更容易写;它在内部也更容易优化。Octave将此操作委托给底层实现,在其他优化中,底层实现可能使用特殊的向量硬件指令,甚至可以并行执行添加。一般来说,如果代码被向量化,那么底层实现就可以更自从地进行假设,以实现更快的执行。
这对于具有“廉价”实体的循环尤为重要。它通常只会对最内部的循环进行向量化,以获得可接受的性能。一般的经验法则是,向量化体的“阶数”应该大于或等于包含循环的“阶”。
作为一个不那么琐碎的例子,而不是
for i = 1:n-1 a(i) = b(i+1) - b(i); endfor
写
a = b(2:n) - b(1:n-1);
这显示了一个重要的通用概念,即使用数组进行索引,而不是在索引变量上循环。详见索引表达式。也要大量使用布尔索引。如果一个条件需要测试,这个条件也可以写成布尔索引。例如,而不是
for i = 1:n if (a(i) > 5) a(i) -= 20 endif endfor
写
a(a>5) -= 20;
它利用了这样一个事实a > 5
生成布尔索引。
尽可能使用元素向量运算符以避免循环(运算符如.*
和.^
). 详见算术运算符.
还要利用这些元素运算符中的广播来避免循环和不必要的中间内存赋值。详见广播.
如果可能,请使用内置函数和库函数。内置和可编译函数非常快。即使使用了m文件库函数,也有可能已经进行了优化,或者在未来的版本中会进行更多优化。
例如,甚至比
a = b(2:n) - b(1:n-1);
是
a = diff (b);
大多数Octave函数都是用ind中的向量和数组参数编写的。如果你查找自己用一个非常简单的操作编写了一个循环,那么这样的函数很可能已经存在了。以下函数经常出现在向量化代码中:
版权所有 © 2024-2025 Octave中文网
ICP备案/许可证号:黑ICP备2024030411号-2