C大调音阶琶音指法:行大调 vs列大调混乱(row major and column major)

我读了很多关于这个的书,我读得越多,我就越困惑。

我的理解:在行主要行连续存储在内存中,在列主要列连续存储在内存中。因此,如果我们有一个数字序列[1, ..., 9],我们想将它们存储在行主要矩阵中,我们得到:

|1, 2, 3|
|4, 5, 6|
|7, 8, 9|

而列主要(纠正我,如果我错了)是:

|1, 4, 7|
|2, 5, 8|
|3, 6, 9|

这实际上是前一个矩阵的转置。

我的困惑:好吧,我没有看到任何区别如果我们迭代两个矩阵(通过第一个中的行和第二个中的列),我们将以相同的顺序覆盖相同的值:1, 2, 3, ..., 9

即使矩阵乘法也是一样的,我们取第一个连续的元素并将它们与第二个矩阵列相乘。所以说我们有矩阵M

|1, 0, 4| 
|5, 2, 7| 
|6, 0, 0|

如果我们将前面的行主要矩阵RM相乘,即R x M,我们将得到:

|1*1 + 2*0 + 3*4, 1*5 + 2*2 + 3*7, etc|
|etc.. |
|etc.. |

如果我们将列主矩阵CM相乘,即C x M通过取C的列而不是其行,我们从R x M得到完全相同的结果

我真的很困惑,如果一切都是一样的,为什么这两个术语甚至存在?我的意思是,即使在第一个矩阵R,我可以看行,并考虑它们列...

我一直在我的线性代数类中学习,我们将第一个矩阵中的行与第二个矩阵中的列相乘,如果第一个矩阵是列大则会改变吗?

任何澄的很感激!

编辑:我遇到的其他主要困惑来源之一是 GLM...所以我将鼠标悬停在它的矩阵类型上并点击 F12 以查看它是如何实现的,在那里我看到一个向量数组,所以如果我们有一个 3x3 矩阵,我们有一个 3 向量的数组。

嗯,我不知道说实话,我写这个打印函数是为了比较我的翻译矩阵和 glm 的,我在最后一行看到 glm 中的翻译向量,我的在最后一列...

enter image description here

这只会增加更多的混乱。你可以清楚地看到glmTranslate矩阵中的每个向量代表矩阵中的一行。所以...这意味着矩阵是行主要的对吗?我的矩阵呢?(我正在使用浮点数组 [16]) 翻译值在最后一列,这是否意味着我的矩阵是列主要的,我现在没有它?试图阻止头部旋转

25

我认为你是混合了一个实现细节与使用,如果你愿意。

让我们从二维数组或矩阵开始:

    | 1  2  3 |
    | 4  5  6 |
    | 7  8  9 |

问题是计算机内存是一个一维的字节数组,为了使我们的讨论更容易,让我们将单个字节分组为四组,因此我们有这样的东西(每个单个,+-+ 表示一个字节,四个字节表示一个整数值(假设 32 位操作系统):

   -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
    |       |       |       |       |       |       |       |       |  
   -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
       \/                   \       /
      one byte               one integer
    low memory    ------>                          high memory

另一种表示方式

所以,问题是如何将二维结构(我们的矩阵)映射到这个一维结构(即内存)上。

行主要顺序:按照这个顺序,我们首先将第一行放在内存中,然后将第二行放在内存中,依此类推。

-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

使用此方法,我们可以通过执行以下算术来找到数组的给定元素。假设我们要访问数组的 $M_{ij} $元素。如果我们假设我们有一个指向数组第一个元素的指针,例如ptr,并且知道列数,例如nCol,我们可以通过以下方式找到任何元素:

     $M_{ij} = i*nCol + j$ 

为了看看这是如何工作的,考虑 M_{02}(即第一行,第三列-记住 C 是基于零的。

      $M_{02} = 0*3 + 2 = 2

所以我们访问数组的第三个元素。

列主要排序:按照这个顺序,我们首先将第一列放在内存中,然后将第二列放在内存中,等等。

-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   1   |   4   |   7   |   2   |   5   |   8   |   3   |   6   |   9   |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

所以,简短的答案-行主要和列主要格式描述了如何将两个(或更高)维数组映射到一维内存数组中。

希望这有助于 T

9

让我们先看看代数;代数甚至没有“内存布局”之类的概念。

从代数 pov,MxN 实数矩阵可以作用于其右侧的 | R ^ N 向量并产生 | R ^ M 向量。

因此,如果你坐在考试中,并给出一个 MxN 矩阵和一个 | R ^ N 向量,你可以用简单的操作将它们相乘并得到一个结果-这个结果是对还是错将不取决于你的教授使用的软件来检查你的结果内部使用列主要还是行主要布局;它只取决于你是否用正确向量的(单列)列计算矩阵的每一行的收缩。

为了产生正确的输出,软件将-无论如何-基本上必须用列向量收缩矩阵的每一行,就像你在考试中所做的那样。

因此,对齐 column-major 的软件和使用 row-major-layout的软件之间的区别不在于它计算的是什么,而仅仅是how

更礼貌地说,这些布局之间关于列向量的主题单行收缩的区别只是确定的方法

Where is the next element of the current row?

对于行主要布局,它是内存中下一个桶中的元素

对于列主布局,它是桶 M 桶中的元素。

就是这样。

向您展示如何在实践中召唤该列 / 行魔术:

你没有用“c ++”标记你的问题,但是因为你提到了“glm”,我假设你可以使用 C ++。

在 C ++ 的标准库中有一个臭名昭著的野兽,称为valarray,除了其他棘手的功能外,它还具有operator[]的重载,其中一个可以使用std::slice(这本质上是一个非常无聊的事情,仅由三个整数类型的数字组成)。

然而,这个小切片的东西,具有访问行主存储列式或列主要存储行式所需的一切-它有一个开始,一个长度和一个步幅-后者代表“到下一个桶的距离”我提到过。

5

不管你用什么:只要保持一致!

row major 或 column major 只是一个约定。没关系。C 使用 row major,Fortran 使用 column。两者都工作。在你的编程语言 / 环境中使用什么是标准的

两个意志不匹配!@ # $东西起来

如果您在存储在 colum major 中的矩阵上使用行主要寻址,则可能会得到错误的元素,读取数组的末尾等...

Row major: A(i,j) element is at A[j + i * n_columns];  <---- mixing these up will
Col major: A(i,j) element is at A[i + j * n_rows];     <---- make your code fubar

这是不正确的说 code 做矩阵乘法是相同的行主要和列主要

(当然矩阵乘法的数学是一样的。)想象一下,你在内存中有两个数组:

X = [x1, x2, x3, x4]    Y = [y1, y2, y3, y4]

如果矩阵存储在主列中,则 X,Y 和 X * Y 为:

IF COL MAJOR: [x1, x3  *  [y1, y3    =   [x1y1+x3y2, x1y3+x3y4
               x2, x4]     y2, y4]        x2y1+x4y2, x2y3+x4y4]

如果矩阵存储在行主要然后 X,Y 和 X * Y 是:

IF ROW MAJOR:  [x1, x2    [y1, y2     = [x1y1+x2y3, x1y2+x2y4;
                x3, x4]    y3, y4]       x3y1+x4y3, x3y2+x4y4];
X*Y in memory if COL major   [x1y1+x3y2, x2y1+x4y2, x1y3+x3y4, x2y3+x4y4]
              if ROW major   [x1y1+x2y3, x1y2+x2y4, x3y1+x4y3, x3y2+x4y4]

这里没有什么深刻的事情,只是两个不同的惯例,就像以英里或公里为单位进行测量一样,无论哪种工作,您都无法在不转换的情况下在两者之间来回翻转!

3

你是对的。系统将数据存储在行主结构还是列主结构中并不重要。这就像一个协议。计算机:“嘿,人类。我要用这种方式存储你的数组。没有问题。嗯?然而,当涉及到性能时,这很重要。考虑以下三件事。

1.大多数数组是按行优先顺序访问的。

2.当您访问内存时,它不是直接从内存中读取的,您首先将一些数据块从内存存储到缓存中,然后将数据从缓存中读取到您的处理器中。

3.如果缓存中不存在您想要的数据,则缓存应从内存中重新提取数据

当缓存从内存中获取数据时,局部性很重要。也就是说,如果将数据稀疏存储在内存中,则缓存应从内存中获取数据的频率更高。此操作会程序的性能,因为访问内存比访问缓存要慢得多(超过 100 倍!)。访问内存越少,程序就越快。因此,此行主要数组效率更高,因为访问其数据更可能是本地的。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(480)
Cornell:加窗法非因果零相位 FIR(cornell matlab)
上一篇
人脸识别算法python:iPhoto人脸识别算法
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(61条)