指针,内存分配:矩阵乘法中的行索引(C编程)

时间:2009-10-14 01:44:22

标签: c

我无法理解问题所指的“行的索引”是什么......你能给我一个例子吗?为什么

sum = sum + a[(row * a_cols) + k] * b[k * b_cols + col]?

谢谢!

double dotProduct(double a[], const unsigned a_rows, const unsigned a_cols,
                  /* a is a matrix with a_rows rows and a_cols columns */
                  double b[], const unsigned b_cols,
                  /* b is also a matrix.  It has a_cols rows and b_cols columns */
                  unsigned row, // an **index of a row of a**
                  unsigned col) // an index of a column of b
{
    int k; // loop variable

    double sum = 0.0; // the result of the dot product is stored here
    k = 0;
    while (k < a_cols) { // recall: a_cols == b_rows
            /* we need to multiply a[row, k] and b[k, col] and add that to sum */
            sum = sum + a[(row * a_cols) + k] * b[k * b_cols + col];
            /* recall a[i,j] is stored at a[(i * a_cols) + j]
                  and b[i,j] is stored at b[(i * b_cols) + j] */
            k += 1;
    }

    return sum;
}

4 个答案:

答案 0 :(得分:2)

编辑我的不好,忘了我的第一个答案,我误解了这个问题......

答案: dotProduct()方法的第5个参数名为 row ,其为 行的索引。
这意味着用于指定“矩阵”a 的一个特定行的0到(a__rows -1)值。 (实际上它可能是1到a__rows的值。这仅仅是一个常规问题;数学人倾向于喜欢“基于1”的索引,程序员更喜欢基于0的值。请参阅Adam Liss对此主题的有趣评论在备注)
由于矩阵a是在一维数组中实现的,因此您需要使用简单的算法来处理由 row 索引的行上的所有单元格。

“公式”是按顺序访问所有这些单元格

for (int c = 0; c < a_cols; c++)
{
    A_Cell_Value = a[row * a_cols + c];
}

应用类似的公式来扫描b的给定的单元格。但是在这种情况下, col ,索引将用作偏移量,b_cols用作因子。具体地,

// not an error this is a_cols which also corresponds to the number of rows of
// matrix b, so that these matrices would be compatible for multiplication    
for (int r = 0; r < a_cols; r++) 
{
     B_Cell_Value = b[(r * b_cols) + col];
}

我认为上面的内容为您提供了对行或列的单元格进行迭代的必要理解。我让你把这一切都放在你的申请中。

一些提示:    - 执行一些参数值检查。这样可以避免在这些矩阵上出现错误。    - 在程序中引入抽象的好方法是引入一个函数,该函数从矩阵维度和两个行和列索引返回矩阵的单个单元格的值。例如:

// returns the matrix's cell value at RowIdx and colIdx
double GetCell(double matrix[], int nbOfRow, int nbOfColumns,
               int rowIdx, int colIdx)
{
   if (rowIdx < 0 || rowIdx >= nbOfRows ||
       colIdx <0 || colIdx >= nbOfColumns
      )
   {
      printf("bad arguments in GetCell()\n");
      return 0;   // print
    }
    return matrix[rowIdx * nbOfColumns + colIdx];
}

以这种方式,您将抽象(=隐藏有关细节)这些丑陋的矩阵线性存储,并能够在点积公式的水平上按行和列索引来解决它们。
换句话说,GetCell()函数基于其对矩阵实现的结构的了解而担心找到正确的单元。它不必知道这个单元格值将用于什么。 DotProduct计算逻辑担心A的哪一系列单元与B的哪一系列单元相乘,在它们的行/列(i / j等)中“自然地”对每个单元寻址“coordonates”并且它没有不需要知道数据如何有效地存储在矩阵实现中。

答案 1 :(得分:1)

从代码中可以看出 a b 是两个矩阵: a 维度为a_rows x a_cols,而 b 的行数和b_cols列数未指定。 (实际上,缺少的b_rows必须等于a_cols才能使数学工作。)该函数正在计算row th 行的dot product a col 中的b th 列中。点积的公式(1&lt; = k &lt; = a_cols):

  

Σ的 [row , k ] B'/强> [ k , col]

在英语中,这意味着您将 row a th 行中的数字乘以col中的数字 b 中的 th 列,一次一对,然后添加产品。

因此,要回答原始问题: row会告诉您{dot}中涉及a中的哪一行。代码将每个矩阵表示为向量(< em> ie 一维数组),Kinopiko的答案解释了如何在特定的行和列中找到数字。 (现在你明白为什么没有评论的“聪明”编程技巧通常不会。)


除此之外:这可能是我解决的最后一个矢量数学问题。维基标记杀死我! : - )

答案 2 :(得分:1)

到目前为止,其他人解释的一个棘手的部分是,如果你有一个24个元素的矢量(线性数组),你可以将它视为一个二维数组 - 实际上,它是一些不同的二维数据阵列。

作为2 x 12阵列:

 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,

作为3 x 8阵列:

 0,  1,  2,  3,  4,  5,  6,  7,
 8,  9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,

作为4 x 6阵列:

 0,  1,  2,  3,  4,  5,
 6,  7,  8,  9, 10, 11,
12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23,

作为一个6 x 4阵列:

 0,  1,  2,  3,
 4,  5,  6,  7,
 8,  9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23,

作为8 x 3阵列:

 0,  1,  2,
 3,  4,  5,
 6,  7,  8,
 9, 10, 11,
12, 13, 14,
15, 16, 17,
18, 19, 20,
21, 22, 23,

或者作为12 x 2阵列:

 0,  1,
 2,  3,
 4,  5,
 6,  7,
 8,  9,
10, 11,
12, 13,
14, 15,
16, 17,
18, 19,
20, 21,
22, 23,

索引表达式a[row * a_cols + col]表示您可以通过将行号乘以矩阵中的列数(从0开始索引行)来标识对应于“row,col”值的向量中的项目,并且然后添加列号(也从0开始索引)。其他语言,例如Fortran,从1而不是零开始索引,因此您可以使用'row-1,col-1'看到类似的计算。

矩阵A具有a_cols列和a_rows行以及矩阵B的条件具有a_cols行和b_cols列意味着您可以将矩阵A x B相乘当然。

答案 3 :(得分:0)

“row”是矩阵a中的行,在此处作为单索引数组完成。如果您将a视为包含a_cols列和a_rows行的矩阵,则行r和列c的元素为a[r*a_cols+c]。此处k是矩阵a中的列索引和矩阵b中的行索引。

sum = sum行下方有一条评论,已经解释了这一点。