我办公室的另一个人和我讨论了哪种复数矩阵阵列格式更有效:交错存储实部和虚部,如
struct {
double real;
double imag;
} Complex foo[m][n];
或分别存储矩阵的实部和虚部:
struct {
double rarray[m][n];
double iarray[m][n];
} CArray foo;
一方面,Complex[][]
更像是一个复数数组的直接表示,并且可能更容易在元素上工作;另一方面,似乎CArray
一般来说效率更高。例如,矩阵乘法可以使用CArray
格式使用组件数组的4个矩阵乘法来完成,而Complex[][]
格式似乎可能因为元素之间的交错而受到影响(因为(a +) bi)*(c + di)=(ad-bc)+(ac + bd)i)。显然,MATLAB使用后一种格式:enter link description here。
还有其他来源可以解决这个问题吗?
答案 0 :(得分:3)
这是应用于复数的古老的“数组结构与数组结构”问题。像大多数性能问题一样,答案通常是“它取决于”,但在这种情况下,我会将我的钱放在结构版本的数组上。
为数值计算选择高效数据结构的关键是在内存中保持您通常需要的数据彼此接近。走出主内存来获取数据很慢;您希望一次将一个数据块引入缓存并尽可能多地使用所有缓存行。因为对于大多数有意义的计算,你几乎总是需要复数的实部和虚数组件,将它们存储为(实数,虚数)对的数组意味着如果你正在处理实数组件,则假想组件几乎总是会坐在那里已经准备好计算的缓存。
但这取决于访问模式。仅仅因为我想象的操作将从复数的数组中受益,并不意味着你想象的是相同的;其他人可以从双阵列方法中受益。如果你对基础A和B有很多操作,如Re(A)* Im(B) - 这意味着什么,我不知道,但仍然 - 那么我认为在CArray方法中可能会明显更快,因为你不必通过加载你不需要的数据来浪费内存带宽(例如,Im(A)和Re(B)。)
最终,这是一个经验问题;如果你知道你的访问模式组合是什么,那么很容易测试这两种方法。但对于我最容易想象的模式,第一种方法会赢。
根据你的链接,Matlab不同意我的事实让我感到惊讶,几乎让我怀疑我的答案。我不是一个巨大的Matlab粉丝,但Matlab人很聪明,并且担心快速进行数值计算。但这是其中一个决定,一旦做出,难以撤消--Matlab现在无法改变这样一个基本的数据布局而不会破坏其他东西,无论是他们自己还是第三方 - 并且可能做出了决定几十年前,缓存性能不那么重要,与某些库的兼容性可能更重要。我注意到像Lapack这样的软件包是基于另一种格式的结构数组(尽管只是隐式地 - 在Fortran中,复合体至少是FORTRAN 66中的原始数据类型)。