Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将大方阵乘以它';s的转置速度比大的方阵相乘要慢。。。如何修复?_C_Matrix_Transpose - Fatal编程技术网

C 将大方阵乘以它';s的转置速度比大的方阵相乘要慢。。。如何修复?

C 将大方阵乘以它';s的转置速度比大的方阵相乘要慢。。。如何修复?,c,matrix,transpose,C,Matrix,Transpose,显然,转置一个矩阵然后将其相乘比仅将两个矩阵相乘要快。然而,我的代码现在没有这样做,我不知道为什么。。。(正常的乘法只是三重嵌套for循环,它给了我大约1.12秒的时间来乘法1000x1000矩阵,而这段代码给了我8倍的时间(因此速度变慢而不是变快)…我现在迷路了,如果有任何帮助,将不胜感激!:D A = malloc (size*size * sizeof (double)); B = malloc (size*size * sizeof (double)); C = malloc (size

显然,转置一个矩阵然后将其相乘比仅将两个矩阵相乘要快。然而,我的代码现在没有这样做,我不知道为什么。。。(正常的乘法只是三重嵌套for循环,它给了我大约1.12秒的时间来乘法1000x1000矩阵,而这段代码给了我8倍的时间(因此速度变慢而不是变快)…我现在迷路了,如果有任何帮助,将不胜感激!:D

A = malloc (size*size * sizeof (double));
B = malloc (size*size * sizeof (double));
C = malloc (size*size * sizeof (double));



/* initialise array elements */
for (row = 0; row < size; row++){
    for (col = 0; col < size; col++){
      A[size * row + col] = rand();
      B[size * row + col] = rand();
    }
  }

t1 = getTime();
A=malloc(size*size*sizeof(double));
B=malloc(尺寸*尺寸*尺寸(双));
C=malloc(尺寸*尺寸*尺寸(双));
/*初始化数组元素*/
用于(行=0;行<大小;行++){
用于(列=0;列<大小;列++){
A[size*行+列]=rand();
B[大小*行+列]=rand();
}
}
t1=getTime();
/*要测量的代码在这里*/

T = malloc (size*size * sizeof(double));

for(i = 0; i < size; ++i) {
  for(j = 0; j <= i ; ++j) {
    T[size * i + j] = B[size * j + i];
  }
}

for (j = 0; j < size; ++j) {
  for (k = 0; k < size; ++k) {
    for (m = 0; m < size; ++m) {
      C[size * j + k] = A[size * j + k] * T[size * m + k];
        }
  }
}


t2 = getTime();
T=malloc(size*size*sizeof(double));
对于(i=0;i对于(j=0;j我看到了两个问题

  • 您只是设置
    C[size*j+k]
    的值,而不是增加它。即使这是计算中的错误,也不会影响性能。此外,您需要初始化
    C[size*j+k]
    0.0
    ,然后再开始最里面的循环。否则,您将增加未初始化的值。这是一个可能导致溢出的严重问题

  • 乘法项是错误的

    请记住,乘法项需要表示:

          C[j, k] += A[j, m] * B[m, k], which is
          C[j, k] += A[j, m] * T[k, m]
    
    而不是

          C[size * j + k] = A[size * j + k] * T[size * m + k];
    
    你需要

          C[size * j + k] += A[size * j + m] * T[size * k + m];
                      //  ^  ^                 ^^^^^^^^^^^^^^^^
                      //  |  |                 Need to get T[k, m], not T[m, k]
                      //  |  ^^^^^^^^^^^^^^^^
                      //  |  Need to get A[j, m], not A[j, k]
                      //  ^^^^ Increment, not set.
    
  • 我认为,除了错误之外,影响性能的主要原因是您使用了
    T[size*m+k]
    。当您这样做时,会有大量内存跳跃(
    m
    是循环中变化最快的变量)来获取数据。当您使用正确的术语时,
    T[size*k+m]
    ,这样会减少,您应该会看到性能的提高

    总之,使用:

    for (j = 0; j < size; ++j) {
       for (k = 0; k < size; ++k) {
          C[size * j + k] = 0.0;
          for (m = 0; m < size; ++m) {
             C[size * j + k] += A[size * j + m] * T[size * k + m];
          }
       }
    }
    
    (j=0;j{ 对于(k=0;k
    您可以通过以下方式获得更高的性能:

    double* a = NULL;
    double* c = NULL;
    double* t = NULL;
    
    for (j = 0; j < size; ++j) {
       a = A + (size*j);
       c = C + (size*j);
       for (k = 0; k < size; ++k) {
          t = T + size*k;
          c[k] = 0.0;
          for (m = 0; m < size; ++m) {
             c[k] += a[m] * t[m];
          }
       }
    }
    
    double*a=NULL;
    double*c=NULL;
    double*t=NULL;
    对于(j=0;j

    PS我没有测试代码。只是给你一些想法。

    在这个测试中,转置可能比乘法运行得慢,因为转置是将数据从内存加载到缓存中的地方,而矩阵乘法会耗尽缓存,至少对于许多现代处理器来说是1000x1000(许多Intel Xeon处理器上的缓存容量为24 MB)

    在任何情况下,转置和乘法都是非常低效的。转置将冲击TLB,因此应该使用32左右的阻塞因子(参见示例代码)

    此外,在x86上,最好是连续写入(因为缓存线锁定和阻塞存储是如何工作的——如果您仔细使用非临时存储,这可能会改变),而在PowerPC的某些变体上,尤其是Blue Gene变体上,您希望连续读取(由于顺序执行,非阻塞存储和直写缓存)。参见示例代码


    最后,我不在乎你说什么(“但我必须这样做”),你需要使用BLAS进行矩阵乘法。故事结束。如果你的主管或其他同事告诉你其他情况,他们是不称职的,在他们彻底再教育之前不应该被允许谈论代码。如果你不想亲自告诉他们,请参阅本帖。

    如果是性能问题你在追求,我建议你使用BLAS而不是重新发明轮子。我特别需要这样做,尽管…:/目标是用连续的单词(在内存中)逐步通过矩阵,这意味着
    k
    必须是
    语句的最里面的
    。顺便说一句,它不够好,无法计算结果的时间。您还需要验证它是否正确:)