5

我需要在 C++ 中实现一个矩阵类,其中一项操作必须是通过 dgemm 进行矩阵乘法。我的教授在课堂上用 C 做过一个例子,但由于某种原因,我无法让它在 C++ 中工作。这是我的头文件matrix.h:

#include <iostream>
#include <stdlib.h>

extern "C" {
#include "blas.h"
}

[blah blah blah, matrix class here; overloaded * operator will do the matrix      
multiplication]

matrix operator* (const matrix &other){

matrix AxB(Nrows, other.Ncolumns, "(" + name + "*" + "other.name" + ")");

char TRANSA = 'N';
char TRANSB = 'N';
int M = Nrows;
int N = other.Ncolumns;
int K = Ncolumns;
double alpha = 1.;
double beta = 0.;

dgemm_ (&TRANSA,
        &TRANSB,
        &M,
        &N,
        &K,
        &alpha,
        data,
        &M,
        other.data,
        &K,
        &beta,
        AxB.data,
        &M);

return AxB;

[blah blah blah, overloaded = operator here; i'm positive this is not the problem 
 since it works for matrix addition]

主功能:

#include "matrix.h"

main(){

// entries of A and B are randomized between 0 and 1
matrix A(5,5);
matrix B(5,5);

matrix C = A*B;

}

现在是 blas.h 头文件:

void dgemm_ (char *TRANSA,
             char *TRANSB,
             int *M,
             int *N,
             int *K,
             double *ALPHA,
             double **A,
             int *LDA,
             double **B,
             int *LDB,
             double *BETA,
             double **C,
             int *LDC);

我将使用此处概述的子例程:http: //www.netlib.org/blas/dgemm.f

基本上,我们在 C 类实现中使用 (double*) calloc(rows*columns, sizeof(double)) 将矩阵构建为一个长数组。

我的 C++ 实现是:

double **data;

data = new double[rows];

for(int i=1; i<=rows; ++i){
    data[i-1] = new double[columns];
}

然后我可以使用 data[i][j] 进行索引。但是由于 dgemm 子例程应该采用双 *A、双 *B 等,但我的矩阵是双 **A 等等,我该如何解决这个问题?

这是我从 valgrind 收到的错误消息:

==18845== Invalid write of size 8
==18845==    at 0x4165C1C: ATL_dgezero (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4149DA7: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas   
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d680 is 8 bytes after a block of size 16 alloc'd
==18845==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind   
/vgpreload_memcheck-x86-linux.so)
==18845==    by 0x8049045: dmatrix::dmatrix(int, int, std::string) (dmatrix.hpp:77)
==18845==    by 0x8049532: dmatrix::operator*(dmatrix const&) (dmatrix.hpp:218)
==18845==    by 0x8048DCB: main (main.cpp:17)
==18845== 
==18845== Invalid write of size 8
==18845==    at 0x4165C1F: ATL_dgezero (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4149DA7: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas   
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d678 is 0 bytes after a block of size 16 alloc'd
==18845==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind 
/vgpreload_memcheck-x86-linux.so)
==18845==    by 0x8049045: dmatrix::dmatrix(int, int, std::string) (dmatrix.hpp:77)
==18845==    by 0x8049532: dmatrix::operator*(dmatrix const&) (dmatrix.hpp:218)
==18845==    by 0x8048DCB: main (main.cpp:17)
==18845== 
==18845== Invalid write of size 8
==18845==    at 0x4165C22: ATL_dgezero (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4149DA7: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas    
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d690 is not stack'd, malloc'd or (recently) free'd
==18845== 
==18845== Invalid write of size 8 
==18845==    at 0x4165C25: ATL_dgezero (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4149DA7: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d688 is not stack'd, malloc'd or (recently) free'd
==18845== 
==18845== Invalid read of size 8
==18845==    at 0x4143D60: ATL_dJIK0x0x0NN0x0x0_aX_bX (in /usr/lib/atlas-base/atlas
/libblas.so.3gf.0)
==18845==    by 0x4149A9D: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478cf80 is not stack'd, malloc'd or (recently) free'd
==18845== 
==18845== Invalid read of size 8
==18845==    at 0x4143D64: ATL_dJIK0x0x0NN0x0x0_aX_bX (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4149A9D: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas    
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d130 is 0 bytes after a block of size 16 alloc'd
==18845==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind 
/vgpreload_memcheck-x86-linux.so)
==18845==    by 0x8049045: dmatrix::dmatrix(int, int, std::string) (dmatrix.hpp:77)
==18845==    by 0x8048D49: main (main.cpp:6)
==18845== 
==18845== Invalid read of size 8 
==18845==    at 0x4143D4C: ATL_dJIK0x0x0NN0x0x0_aX_bX (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4149A9D: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d678 is 0 bytes after a block of size 16 alloc'd
==18845==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind 
/vgpreload_memcheck-x86-linux.so)
==18845==    by 0x8049045: dmatrix::dmatrix(int, int, std::string) (dmatrix.hpp:77)
==18845==    by 0x8049532: dmatrix::operator*(dmatrix const&) (dmatrix.hpp:218)
==18845==    by 0x8048DCB: main (main.cpp:17)
==18845== 
==18845== Invalid write of size 8
==18845==    at 0x4143D93: ATL_dJIK0x0x0NN0x0x0_aX_bX (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4149A9D: ATL_dNCmmJIK (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x415BE8E: ATL_dgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x4182F54: ATL_dptgemm_nt (in /usr/lib/atlas-base/atlas 
/libblas.so.3gf.0)
==18845==    by 0x4183140: ATL_dptgemm (in /usr/lib/atlas-base/atlas/libblas.so.3gf.0)
==18845==    by 0x40818F6: atl_f77wrap_dgemm_ (in /usr/lib/atlas-base/atlas   
/libblas.so.3gf.0)
==18845==    by 0x4E4E0004: ???
==18845==  Address 0x478d678 is 0 bytes after a block of size 16 alloc'd
==18845==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind 
/vgpreload_memcheck-x86-linux.so)
==18845==    by 0x8049045: dmatrix::dmatrix(int, int, std::string) (dmatrix.hpp:77)
==18845==    by 0x8049532: dmatrix::operator*(dmatrix const&) (dmatrix.hpp:218)
==18845==    by 0x8048DCB: main (main.cpp:17)
==18845== 
==18845== Invalid read of size 8
==18845==    at 0x8048DEA: main (main.cpp:19)
==18845==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==18845== 
==18845== 
==18845== Process terminating with default action of signal 11 (SIGSEGV)
==18845==  Access not within mapped region at address 0x0
==18845==    at 0x8048DEA: main (main.cpp:19)
==18845==  If you believe this happened as a result of a stack
==18845==  overflow in your program's main thread (unlikely but
==18845==  possible), you can try to increase the size of the
==18845==  main thread stack using the --main-stacksize= flag.
==18845==  The main thread stack size used in this run was 8388608.
==18845== 
==18845== HEAP SUMMARY:
==18845==     in use at exit: 3,581 bytes in 39 blocks
==18845==   total heap usage: 49 allocs, 10 frees, 7,760 bytes allocated
==18845== 
==18845== LEAK SUMMARY:
==18845==    definitely lost: 128 bytes in 4 blocks
==18845==    indirectly lost: 0 bytes in 0 blocks
==18845==      possibly lost: 88 bytes in 4 blocks
==18845==    still reachable: 3,365 bytes in 31 blocks
==18845==         suppressed: 0 bytes in 0 blocks
==18845== Rerun with --leak-check=full to see details of leaked memory
==18845== 
==18845== For counts of detected and suppressed errors, rerun with: -v
==18845== ERROR SUMMARY: 111 errors from 9 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

直到我尝试实现 dgemm 矩阵乘法,我没有错误也没有泄漏,所以我很确定我所有的麻烦都在于 dgemm 实现

4

2 回答 2

1

C 版本的内存布局与 C++ 版本的内存布局不同。由于 BLAS 期望 C 版本使用的那种布局,您的 C++ 版本将无法工作。

因此,您还需要在 C++ 版本中分配一个大的一维数组;您可以重载 operator() 以获得二维数组的索引。或者对于生产代码,使用诸如Eigen之类的库。

于 2012-11-05T07:27:16.327 回答
0

抱歉,我没有意识到在响应时按 Enter 会发送响应。

我更改了索引:

double *data;

data = new double[rows*columns];

然后每次我想索引它时,我只是对 data[(i-1)*columns + (j-1)] 进行行主要索引。该代码现在确实可以工作,并且编译时出现 0 个错误和 0 个内存泄漏!唯一的问题是我现在得到一个完全乱码的结果。

这是否与 fortran 执行列优先排序而我执行行优先的事实有关?我将如何调和这一点?

于 2012-11-05T07:54:42.160 回答