【问题标题】:Complex number array format efficiency for common operations常见操作的复数数组格式效率
【发布时间】:2012-09-05 22:17:04
【问题描述】:

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

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

还有其他处理这个问题的来源吗?

【问题讨论】:

    标签: matrix format storage numerical complex-numbers


    【解决方案1】:

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

    为数值计算选择有效的数据结构的关键是让您通常同时需要的数据在内存中彼此靠近。出主存取数据慢;您希望一次将一大块数据引入缓存并尽可能多地使用所有该缓存行。由于您几乎总是需要复数的实部和虚部来进行最有意义的计算,因此将它们存储为(实部,虚部)对的数组意味着如果您正在处理实部,虚部几乎总是会在缓存中准备好进行计算。

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

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

    根据您的链接,Matlab 不同意我的观点,这让我感到惊讶,几乎让我怀疑我的答案。我不是一个巨大的 Matlab 粉丝,但 Matlab 人很聪明,并且关心使数值计算快速。但这是其中一个决定,一旦做出,就很难撤销——Matlab 现在无法改变这样一个基本的数据布局,而不破坏他们自己和第三方的无数其他东西——而且这个决定可能已经做出几十年前,缓存性能不太重要,与某些库的兼容性可能更重要。我注意到像 Lapack 这样的包是基于另一种格式,结构数组(尽管只是隐含的 -- 在 Fortran 中,至少从 FORTRAN 66 开始,complex 一直是一种原始数据类型)。

    【讨论】:

    • 在某些语言(如 Java)中可能最好的另一个选项是将 NxN 矩阵表示为 Nx2N 双精度数组。这将允许类似于结构数组的内存布局,即使 Java 不支持结构类型。
    • 你的评论很有趣,今年早些时候 MATLAB 刚刚更改为另一种格式——为了与用户的 C/C++ 代码兼容,需要时有大量额外的数据副本。
    猜你喜欢
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 2011-07-23
    • 2013-10-05
    • 2021-01-04
    相关资源
    最近更新 更多