在对密集矩阵计算进行编程时,是否有任何理由要选择超过行的主布局的行主布局?
我知道,根据所选矩阵的布局,我们需要编写适当的代码以有效地将高速缓存用于速度目的。
以行为主的布局似乎更自然,更简单(至少对我而言)。但是用Fortran编写的LAPACK之类的主要库都使用列的主要布局,因此必须有一些选择的理由。
在对密集矩阵计算进行编程时,是否有任何理由要选择超过行的主布局的行主布局?
我知道,根据所选矩阵的布局,我们需要编写适当的代码以有效地将高速缓存用于速度目的。
以行为主的布局似乎更自然,更简单(至少对我而言)。但是用Fortran编写的LAPACK之类的主要库都使用列的主要布局,因此必须有一些选择的理由。
Answers:
在不考虑任何现有软件的情况下,从代码角度来看,没有理由偏爱列专业而不是行专业。但是,大多数数学文献都是以将向量存储为列而不是行的方式将向量分组为矩阵的方式编写的。例如,当你写的完全特征方程时,X矩阵包含以列写出的所有特征向量。您永远不会真正看到它是用其他方式写的(尽管我听说统计人员喜欢行向量)。因此,很自然,最早的软件采用列主格式,因此,如果您有一个由一组向量组成的矩阵,则任何单个向量的存储都是连续的。因此,我认为传统一直延续到今天,并且,如果您想与ye Forde Fortran进行交互,则希望使用column major。因此,几乎所有高效的数值线性代数都是在列专业中完成的。
C是行专业的原因在某种程度上是其数组语法的结果。您将3行2列的数组声明为double a[3][2]
,而较后的索引的变化要快于较早的索引,这对于2D数组而言使其成为主要行。结合自然的西方阅读顺序(从左到右),使行专业显得更加自然。
列大顺序似乎更自然。例如,假设您想将电影按图片保存到文件中,那么您使用的是列顺序,这是非常直观的,没有人会按行大顺序保存它。
如果您是C / C ++的程序员,则应使用默认列优先顺序对矩阵(Eigen,Armadillo等)使用更高级别的库。尽管C / C ++提供了一些提醒矩阵索引的功能,但只有疯子才会使用行优先级高的原始C指针。
为简单起见,所有具有大行顺序的事物都应至少视为奇怪的形式。逐个切片是自然顺序,它表示列优先顺序(如Fortran)。我们的父亲/母亲选择它们的理由非常充分。
不幸的是,由于缺乏经验,在以行为主的顺序创建了几个有趣的库之前。
为了澄清召回行优先顺序的定义,其中右索引在内存中一步改变得更快,例如A(x,y,z)是z索引,这意味着在内存中来自不同切片的像素是相邻的,不想。对于电影A(x,y,t),最后一个索引是时间t。不难想象,以行为主模式保存电影根本是不可能的。
现在想象一下以下算法:
for i from 1 to m
for j from 1 to n
do something with m(i,j)
如果使用行优先顺序,则它将遍历所有线性索引 顺序地,导致良好的内存局部性,而如果使用列优先顺序,则连续的内存访问将分散在内存中。后果可能非常严重,尤其是当虚拟内存/交换进入现场时。
结论:
是的,它很重要,但是选择取决于获取数据的方式。对于前面的示例,如果使用列顺序,则只需交换两个循环即可。
经验法则:快速变化的索引应映射到内存中的连续位置。
更重要的是,衡量/基准测试选择的影响至关重要,因为它取决于许多参数(数据大小,缓存大小,所用语言将多个索引映射到线性索引的方式,操作方式)。系统管理虚拟内存,循环嵌套在您使用的线性代数库中的方式...)