Matrix 常见操作的复数数组格式效率

Matrix 常见操作的复数数组格式效率,matrix,format,storage,numerical,complex-numbers,Matrix,Format,Storage,Numerical,Complex Numbers,我办公室的另一个人和我讨论了哪种复数矩阵数组格式更有效:存储交错的实部和虚部,如 struct { double real; double imag; } Complex foo[m][n]; 或者通过分别存储矩阵的实部和虚部: struct { double rarray[m][n]; double iarray[m][n]; } CArray foo; 一方面,Complex[][]更直接地表示复数数组,在元素方面可能更容易操作;另一方面,CArray似乎

我办公室的另一个人和我讨论了哪种复数矩阵数组格式更有效:存储交错的实部和虚部,如

struct {
    double real;
    double imag;
} Complex foo[m][n];
或者通过分别存储矩阵的实部和虚部:

struct {
    double rarray[m][n];
    double iarray[m][n];
} CArray foo;
一方面,
Complex[][]
更直接地表示复数数组,在元素方面可能更容易操作;另一方面,
CArray
似乎总体上效率更高。例如,矩阵乘法可以使用使用
CArray
格式的组件阵列的4个矩阵乘法来完成,而
复杂[]][]
格式似乎由于元素之间的交错而可能受到影响(因为(a+bi)*(c+di)=(ad-bc)+(ac+bd)i)。显然,MATLAB使用后一种格式:

是否有其他来源处理这个问题?

这是一个古老的“数组结构vs数组结构”问题,适用于复数。与大多数性能问题一样,一般来说,答案是“视情况而定”,但在这种情况下,我会把钱花在结构数组版本上

为数值计算选择有效的数据结构的关键是在内存中保持通常同时需要的数据彼此接近。到主存储器获取数据的速度很慢;您希望一次将一块数据放入缓存,并尽可能多地使用所有缓存线。因为你几乎总是需要复数的实部和虚部来进行最有意义的计算,所以将它们存储为(实部,虚部)对数组意味着,如果你在处理实部,虚部几乎总是放在缓存中,随时可以进行计算

但这取决于访问模式。仅仅因为我想象的运算将受益于复数数组,并不意味着你想象的是相同的运算;其他人可以从双阵列方法中获益。如果你对矩阵A和B有很多操作,比如Re(A)*Im(B)-这意味着什么,我不知道,但仍然-那么我认为在CArray方法中,一个操作可能要快得多,因为你不必通过加载不需要的数据来浪费内存带宽(例如,Im(A)和Re(B)。)

归根结底,这是一个经验问题;如果您知道访问模式的组合是什么,那么测试这两种方法就很容易了。但对于我最容易设想的模式,第一种方法将获胜


根据你的链接,Matlab不同意我的观点,这一事实让我大吃一惊,几乎让我怀疑我的答案。我不是Matlab的超级粉丝,但是Matlab的人很聪明,他们关心的是如何快速地进行数值计算。但这是其中的一个决定,一旦做出,就很难撤销——Matlab现在无法改变这样一个基本的数据布局,而不破坏无数其他东西,他们自己的和第三方的——这个决定可能是在几十年前做出的,当时缓存性能不那么重要,与某些库的兼容性可能更重要。我注意到,像Lapack这样的包是基于另一种格式,即结构数组(虽然只是隐式的——在Fortran中,complex至少从Fortran 66开始就是一种原始数据类型)。

在某些语言(如Java)中最好的另一种选择是将NxN矩阵表示为Nx2N双精度数组。这将允许内存布局类似于结构数组,即使Java不支持结构类型。有趣的是,您的评论是,MATLAB在今年早些时候刚刚更改为另一种格式——为了与用户的C/C++代码兼容,在必要时添加了大量额外的数据副本。