linux如何编译fortran子程序,linux下Fortran编译Lapack、clapack库及使用的方法

apt安装:

$ sudo apt install libblas-dev liblapacke-dev liblapack-dev libtmglib-dev libatlas-dev libatlas-base-dev libblacs-mpi-dev libopenblas-base libopenblas-dev libf2c2-dev

一、获取lapack源代码

wget http://www.netlib.org/lapack/lapack-3.6.1.tgz

二、解压后编译

cd /mybk/lapack-3.6.1

cp make.inc.example make.inc

make后得到liblapack.a  librefblas.a  libtmglib.a

三、拷贝到系统库路径如/opt/local/lib

四、测试:

tetst.f

! gfortran -o test test.f -L/opt/local/lib -llapack -lrefblas

program main

implicit none

real :: a(3,3),b(3)

integer :: v(3),iflag

!external sgesv

a=reshape([2.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,4.0],[3,3])

b=[998.0,999.0,1000.0]

print *,'a=',a

print *,'b=',b

call sgesv(3,1,a,3,v,b,3,iflag)

print *,'solve=',b

end program main

gfortran -o test test.f -L/opt/local/lib -llapack -lrefblas

$ ./test

a=   2.00000000       0.00000000       0.00000000       0.00000000       3.00000000       0.00000000       0.00000000       0.00000000       4.00000000

b=   998.000000       999.000000       1000.00000

solve=   499.000000       333.000000       250.000000

test2.s

! gfortran -o test2 test2.f -L/opt/local/lib -llapack -lrefblas

program Console1

external dgesv

integer n, lda, nrhs, ldb

parameter (n=2,lda=2,nrhs=1,ldb=2)

double precision A(lda,n)

double precision b(ldb,nrhs)

character byebye

integer ipiv(n), info, i, j

A(1,1)=1

A(1,2)=2

A(2,1)=3

A(2,2)=4

B(1,1)=5

B(2,1)=6

write(*,*) 'Hello World'

call dgesv(n,nrhs,A,lda,ipiv,b,ldb,info)

write(*,*) 'INFO =', info

write(*,*) ((A(i,j),i=1,lda),j=1,n)

write(*,*) ((B(i,j),i=1,ldb),j=1,nrhs)

write(*,*) "END OF PROGRAM..."

end program Console1

$ gfortran -o test2 test2.f -L/opt/local/lib -llapack -lrefblas

$ ./test2

Hello World

INFO =           0

3.0000000000000000       0.33333333333333331        4.0000000000000000       0.66666666666666674

-3.9999999999999987        4.4999999999999991

或直接安装

sudo apt install libopenblas-base libopenblas-dev liblapacke liblapacke-dev liblapack3 liblapack-dev libtmglib3 libtmglib-dev

编译: gfortran -o test2 test2.f -llapack

五、CLAPACK的安装与简单使用

CLAPACK是没有源的,只能从其主页上下载源码自己编译http://www.netlib.org/clapack/clapack.tgz,解压。在其目录下的INSTALL目录中有make.inc的范本文件,比如在linux下就是make.inc.LINUX,将这个文件拷到CLAPACK目录下并改名为make.inc。

首先编译F2CLIBS,用于将fortran转换为c语言,在CLAPACK目录下,make f2clib,在

CLAPACK/F2CLIBS下就会生成libf2c.a。

编译tmglib,在CLAPACK目录下,make tmglib,会生成CLAPACK/tmglib_LINUX.a。

编译blas,在CLAPACK目录下,make blaslib,会生成CLAPACK/blas_LINUX.a。

最后是编译CLAPACK,make,会生成CLAPACK/lapack_LINUX.a

CLAPACK下的clapack.h就是所需要的头文件,除此之外还需要的一个头文件是F2CLIBS/f2c.h。

为方便使用,将必要的include文件和lib文件集中到一个目录下(如/mybk/CLAPACK):

~/prg/Fortran95/lapack$ tree /mybk/CLAPACK

/mybk/CLAPACK

├── include

│   ├── blaswrap.h

│   ├── clapack.h

│   └── F2CLIBS

│   └── f2c.h

└── lib

├── blas_LINUX.a

├── lapack_LINUX.a

├── libcblaswr.a

├── libf2c.a

└── tmglib_LINUX.a

现在就通过使用CLAPACK中的一个函数sgesv_解线性方程组来学习一下使用的方法。

包括此函数在内的所有函数可以在CLAPACK/SRC下找到源代码,并在代码中有函数参数的说明信息。sgesv_的代码文件就是sgesv.c。

int sgesv_(integer *n, integer *nrhs, real *a, integer *lda, integer *ipiv, real *b, integer *ldb, integer *info)

sgesv_的功能是使用LU分解法解线性方程组AX=B,其中A是一个n*n的方阵。

integer *n, 方程的个数,也就是A的行数和列数

integer *nrhs, B的列数

real *a, 存储矩阵A数据的一维数组,在fortran中,数组是列主序存储,在此a中的二维数据也必须是列主序

integer *lda, 等于n

integer *ipiv, 一个输出数据数组,数组大小是n,具体什么功能不太明白,但是似乎不影响最后结果,谁明白请告诉我

real *b,存储矩阵B数据的一维数组,在fortran中,数组是列主序存储,在此b中的二维数据也必须是列主序

integer *ldb, 等于n

integer *info,输出参数,如果返回此参数为0,表示函数正常退出,否则表示出错。

代码:

// g++ -o clapackdemo clapackdemo.cpp -I/mybk/CLAPACK/include /mybk/CLAPACK/lib/lapack_LINUX.a /mybk/CLAPACK/lib/blas_LINUX.a /mybk/CLAPACK/lib/tmglib_LINUX.a /mybk/CLAPACK/lib/libf2c.a

#include

#include

using namespace std;

#include

//因为程序是C++,而CLAPACK是C语言写的,所以在此处用extern关键字

extern"C"

{

#include

}

int main(void){

integer M=3;

integer N=1;

real a[9]={4,3,11,2,-1,0,-1,2,3};

real b[3]={2,10,8};

integer lda;

integer ldb;

integer INFO;

lda=M;

ldb=M;

integer ipiv[M];

sgesv_(&M, &N, a, &lda,ipiv, b, &ldb, &INFO);

if(INFO==0)

for(int i=0;i

cout<

else

cout<

return EXIT_SUCCESS;

}

编译运行:

$ g++ -o clapackdemo clapackdemo.cpp -I/mybk/CLAPACK/include /mybk/CLAPACK/lib/lapack_LINUX.a /mybk/CLAPACK/lib/blas_LINUX.a /mybk/CLAPACK/lib/tmglib_LINUX.a /mybk/CLAPACK/lib/libf2c.a

$ ./clapackdemo

-14

56

54

c语言openblas:

//g++ -o openblastest1 openblastest1.cpp `pkg-config --cflags --libs blas-netlib`

#include

#include

#include

#include

// 随机生成20以内的给定尺寸数组

static void RandomFill(std::vector& numbers,size_t size);

// 打印数组元素的函数

static void Print(const std::vector& numbers);

// vector是一维的,输出是个矩阵,那输出的时候就要指定有几行几列

static void Print(const std::vector& numbers, int rows, int cols);

// 寻找数组中最大的那个元素的索引和值

static void TestLevel1();

// 测试Level2里面最常用的函数:向量和矩阵的乘积

static void TestLevel2();

static void TestLevel3();

int main(int argc, const char * argv[]) {

TestLevel1();

std::cout <

TestLevel2();

std::cout <

TestLevel3();

return 0;

}

void RandomFill(std::vector& numbers, size_t size) {

// 预分配size的缓冲区,这样性能相对更好一点

numbers.resize(size);

for (size_t i = 0; i != size; ++ i) {

numbers[i] = static_cast(rand() % 20);

}

}

static void TestLevel1() {

const int VECTOR_SIZE = 4;

std::vector fv1;

RandomFill(fv1, VECTOR_SIZE);

Print(fv1);

/**

从数组里面找出最大的那个数的索引:cblas_isamax()属于Level1的函数

VECTOR_SIZE 数组长度

fv1.data 数组缓冲区指针的首地址,怎么获得fv1内部缓冲区呢,用fv1.data

third params: 跳跃数量,两个元素之间间隔几个元素,也就是每处理一个元素之后,+1得到下一个元素,如果想跳过一个元素 +2

*/

size_t maxIndex = cblas_isamax(VECTOR_SIZE, fv1.data(), 1);

std::cout << maxIndex << std::endl;

std::cout << fv1[maxIndex] << std::endl;

}

/*

Prints:

7 9 13 18

3

18

*/

/*

测试Level2里面最常用的函数:向量和矩阵的乘积

*/

static void TestLevel2()

{

// 假设我们有一个三行二列的矩阵

const int M = 3;

const int N = 2;

/*

A(M*N),x(N*1), y(M*1)

我们定义三个矩阵a、x、y

a:M*N的矩阵:维度为M*N矩阵

x:N*1的矩阵,实际上是一个向量,维度为N矩阵

y:M*1的矩阵,实际上是长度为M的向量,维度为M的矩阵

*/

std::vector a;

std::vector x;

std::vector y;

RandomFill(a, M * N);

RandomFill(x, N);

RandomFill(y, M);

std::cout << "A" << std::endl;

Print(a, M, N);

std::cout << "x" << std::endl;

Print(x);

std::cout << "y" << std::endl;

Print(y);

/*

我们的目标是想计算这么一个公式:

y := alpha * A * x + beta * y

A:是一个矩阵,x是一个向量,所以我希望说去计算一个矩阵和向量的乘积。alpha是一个乘积的缩放,

beta是对y的缩放,

相当于把y里面的数字乘以beta,再加上A矩阵和向量的乘积。

那这边有一个特例,假如我y里面都是0,或这beta是0的情况下,我就可以把公式看成:

// y := alpha * A * x

这个函数名称为:cblas_sgemv()

// s:single 单精度浮点数

// ge: 是一个乘法

// m: matrix

// v: vector

*/

/**

参数解释:

param CblasRowMajor 行主序还是列主序,默认行主序,何为主序:即数组存储元素的方式--按行存储还是按列存储,行主序:00,01,列主序00,10

param CblasNoTrans 矩阵是否需要转置,不需要转置,如果需要转置的话,运算的时候它会自动做转置

param M 矩阵的行数

param N 矩阵的列数

param 1.0f alpha ,我们设为1

param a.data a矩阵的缓冲区首地址

param lda a矩阵的列数

param x.data x矩阵的缓冲区首地址

param 1 x里面每次跳跃累加的个数,默认为1

param 2.0f beta对y的缩放值

param y.data y矩阵的缓冲区首地址

param 1 y里面每次跳跃累加的个数,默认为1

*/

int lda = N;

cblas_sgemv(CblasRowMajor, CblasNoTrans, M, N, 1.0f, a.data(), lda, x.data(), 1, 2.0f, y.data(), 1);

std::cout << "result y" << std::endl;

Print(y);

}

/*

Prints:

A

7 9

13 18

10 12

x

4 18

y

3 9 0

result y

196 394 256

*/

void Print(const std::vector& numbers) {

for (float number : numbers) {

std::cout << number << ' ';

}

std::cout << std::endl;

}

void Print (const std:: vector& numbers ,int rows, int cols) {

for (int row =0; row != rows; ++ row) {

for (int col = 0; col != cols; ++ col) {

// 取出每一列的数字

std::cout << numbers[row * cols + col] << ' ';

}

// 没输出一行之后换一行

std::cout << std::endl;

}

}

/**

计算两个矩阵的乘积

*/

static void TestLevel3() {

// 我们希望计算两个矩阵的乘积,我们就需要定义三个参数M、N、K。

const int M = 3;

const int N = 2;

const int K = 4;

std::vector a;

std::vector b;

std::vector c;

RandomFill(a, M * K);

RandomFill(b, K * N);

RandomFill(c, M * N);

// 输出A、B、C 三个矩阵

std::cout << "A" << std::endl;

Print(a, M, K);

std::cout << "B" << std::endl;

Print(b, K, N);

std::cout << "C" << std::endl;

Print(c, M, N);

/*

我们的目标是计算这么一个公式:

// C := alpha * A * B + beta * C

// 如果只想做两个矩阵的乘法,beta设成0就好了,变为如下式子:

// C := alpha * A * B

*/

/*

函数释义:

sgemm:矩阵间的单精度乘法

s:single 单精度

ge:general 一般的,普通的

m:matix 矩阵

m:multiplication 乘法

*/

/**

参数释义:

param CblasRowMajor 行主序还是列主序,默认行主序

param CblasNoTrans A需不需要转置,不需要

param CblasNoTrans B需不需要转置,不需要

param M 系数M

param N 系数N

param K 系数K

param 1.0f alpha 设为1

param a.data a的缓冲区首地址

param lda a的列数

param b.data b的缓冲区首地址

param ldb b的列数

param 1.0f beta 设为1

param c.data c的缓冲区首地址

param ldc c的列数

*/

int lda = K;

int ldb = N;

int ldc = N;

cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, 1.0f, a.data(), lda, b.data(), ldb, 1.0f, c.data(), ldc);

std::cout << "Result C" << std::endl;

// 三行四列的矩阵 * 四行二列的矩阵 + 三行二列的矩阵,结果为一个三行二列的矩阵

Print(c, M, N);

}

/*

Prints:

A

7 9 13 18

10 12 4 18

3 9 0 5

B

12 2

7 3

7 9

0 12

C

3 9

9 17

0 13

Result C

241 383

241 325

99 106

*/

编译运行:

$ g++ -o openblastest1 openblastest1.cpp `pkg-config --cflags --libs blas-netlib`

$ ./openblastest1

3 6 17 15

2

17

-------------------------------------

A

13 15

6 12

9 1

x

2 7

y

10 19 3

result y

151 134 31

-------------------------------------

A

6 0 6 12

16 11 8 7

9 2 10 2

B

3 7

15 9

2 2

18 9

C

7 13

16 11

2 9

Result C

253 175

371 301

115 128

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值