我正在编写一个函数,它调用Fortran函数进行复杂的矩阵矩阵乘法。我正在调用CGEMM_和ZGEMM_函数进行复数乘法。由于所有xGEMM_函数基本相同,我将代码从SGEMM_复制到CGEMM__和ZGEMM_。唯一的变化是各自的数据类型。 SGEMM_和DGEMM_函数工作正常,但CGEMM_抛出错误。所有输入都是相同的。
** On entry to CGEMM parameter number 13 had an illegal value
和zgemm_ throws
** On entry to ZGEMM parameter number 1 had an illegal value
我真的不知道发生了什么。这是liblapack包中的某种错误吗?我正在使用liblapack-dev包。我制作了一个较小版本的大代码,我仍然得到了与CGEMM_相同的错误。
我正在运行一个32位系统,并想知道这是不是问题。
代码:
#include<iostream>
using namespace std;
#include<stdlib.h>
#include<string.h>
#include<complex>
typedef complex<float> c_float;
extern "C"
{c_float cgemm_(char*,char*,int*,int*,int*,c_float*, c_float[0],int*,c_float[0],int*,c_float*,c_float[0],int*);//Single Complex Matrix Multiplication
}
c_float** allocate(int rows, int columns)
{
c_float** data;
// Allocate Space
data = new c_float*[columns]; //Allocate memory for using multidimensional arrays in column major format.
data[0] = new c_float[rows*columns];
for (int i=0; i<columns; i++)
{
data[i] = data[0] + i*rows;
}
// Randomize input
for (int i=0; i<columns; i++)
{for (int j=0; j<rows; j++)
{
data[j][i] =complex<double>(drand48()*10 +1,drand48()*10 +1); //Randomly generated matrix with values in the range [1 11)
}
}
return(data);
}
// Destructor
void dest(c_float** data)
{
delete [] data[0];
delete [] data;
}
// Multiplication
void mult(int rowsA,int columnsA, int rowsB,int columnsB)
{
c_float **matA,**matB,**matC;
char transA, transB;
int m,n,k,LDA,LDB,LDC;
c_float *A,*B,*C;
c_float alpha(1.0,0.0);
c_float beta(0.0,0.0);
matA = allocate(rowsA,columnsA);
matB = allocate(rowsB,columnsB);
matC = allocate(rowsA,columnsB);
transA = 'N';
transB = 'N';
A = matA[0];
B = matB[0];
m = rowsA;
n = columnsB;
C = matC[0];
k = columnsA;
LDA = m;
LDB = k;
LDC = m;
cout<<"Matrix A"<<endl;
for (int i=0; i<rowsA; i++)
{for (int j=0; j<columnsA; j++)
{
cout<<matA[i][j];
cout<<" ";
}cout<<endl;
}
cout<<"Matrix B"<<endl;
for (int i=0; i<rowsB; i++)
{for (int j=0; j<columnsB; j++)
{
cout<<matB[i][j];
cout<<" ";
}cout<<endl;
}
cgemm_(&transA,&transB,&m,&n,&k,&alpha,A,&LDA,B,&LDB,&beta,C,&LDC);
cout<<"Matrix A*B"<<endl;
for (int i=0; i<rowsA; i++)
{for (int j=0; j<columnsB; j++)
{
cout<<matC[i][j];
cout<<"";
}
cout<<endl;
}
dest(matA);
dest(matB);
dest(matC);
}
main()
{
mult (2,2,2,2);
}
输出和valgrind报告如下:
-----------------------------------------
Compilation using g++ -g -o matrix Matrix_multiplication.cpp -lblas -llapack -lgfortran
./matrix gives
Matrix A
(1.00985,1) (1.91331,4.64602)
(2.76643,1.41631) (5.87217,1.92298)
Matrix B
(5.54433,6.2675) (6.6806,10.3173)
(9.31292,3.33178) (1.50832,6.56094)
** On entry to CGEMM parameter number 1 had an illegal value
Valgrind output looks like
==4710== Memcheck, a memory error detector
==4710== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4710== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4710== Command: ./o
==4710== Parent PID: 3337
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x46DD683: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46DD686: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x46DD7B1: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46DD7B4: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x46DD859: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710== at 0x46DD85C: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710== by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710== by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710== Uninitialised value was created by a stack allocation
==4710== at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710==
==4710== HEAP SUMMARY:
==4710== in use at exit: 120 bytes in 6 blocks
==4710== total heap usage: 43 allocs, 37 frees, 13,897 bytes allocated
==4710==
==4710== LEAK SUMMARY:
==4710== definitely lost: 0 bytes in 0 blocks
==4710== indirectly lost: 0 bytes in 0 blocks
==4710== possibly lost: 0 bytes in 0 blocks
==4710== still reachable: 120 bytes in 6 blocks
==4710== suppressed: 0 bytes in 0 blocks
==4710== Rerun with --leak-check=full to see details of leaked memory
==4710==
==4710== For counts of detected and suppressed errors, rerun with: -v
==4710== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
编辑:使用可以运行的代码修改了问题。问题仍然存在,问题的性质没有改变。
答案 0 :(得分:1)
关于Fortran中字符变量长度的答案基本上是正确的,但这不是你的问题。 blas库中函数的固定长度字符变量可能不会从函数参数中读取长度。我检查了一个函数,即使在-O0
,长度也是编译时常量。
您的特定问题的原因是定义c_float cgemm_(...
,您告诉编译器cgemm_
返回c_float
。通常,返回值放在寄存器中,但是当它们太大时,它们也可以进入堆栈。在你的情况下,在32位系统上,这似乎是8字节c_float
的情况。将函数定义为void cgemm_
(应该是)或甚至int cgemm_
(将使用寄存器)解决了这个问题。
带回家的消息是&#34;不要这样做&#34;,因为这是一种hackish的呼叫方式,并且在处理不同的平台/编译器时会引起麻烦。使用cblas接口或用于blas操作的C ++库要好得多。
答案 1 :(得分:0)
我没有看到transA
或transB
字符串的长度传递给xgemm_
来电。
Character
个假人伴随着一个隐藏的&#39;长度论证。例如,GCC 4.9.0使用的惯例在此更详细地描述:
https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gfortran/Argument-passing-conventions.html
这些隐藏参数在参数列表中的定位取决于平台。在Linux上,它们被放置在所有显式参数之后。
考虑s.f90
Subroutine s(c, r)
Character (*), Intent (In) :: c
Real, Intent (In) :: r
Print '(3A,I0,A)', 'c = "', c, '", (len(c)=', len(c), ')'
Print *, 'r = ', r
End Subroutine
和main.c
#include <string.h>
int main(void)
{
char c[1+1];
float r=4.2;
strcpy(c,"A");
s_(c,&r,1);
}
为了在Linux上运行,我传递1
作为s
的(隐藏在Fortran中)第三个参数,表示我的字符串的长度。
使用gfortran
进行编译并运行
> gfortran -g main.c s.f90 && ./a.out
c = "A", (len(c)=1)
r = 4.19999981
您的xgemm_
来电可能应该是...,&LDC,1,1);
吗?