分享
 
 
 

科学计算与可视化(VC中调用VF详解)

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

1.VC++与Fortran的混合编程

目前VC和VF都是基于WINDOWS的IDE开发环境,并且在安装同一版本的Fortran时会自动集成到VS的开发环境,这样就给我们在进行调用Fortran时提供了三种不同的方法。

1.1 同一工程下包含不同语言的文件

集成后的编译器可以根据不同的扩展名选择编译方式,生成目标代码文件.OBJ,然后按照指定的调用方式进行链接,生成可执行文件.EXE。

在2中我们提到调用规则,在C语言中调用Fortran的函数或模块,必须在函数名前面冠以_stdcall关键字作为调用方式①,这样编译器会给我们处理包括参数传递顺序、参数传递方式、堆栈处理和命名修饰等问题。而在C++语言中,尽管在开发C++语言时考虑兼容C方式,即C++对函数的调用规则与C是一致的,但是C++在命名转换上与C语言是不一致的。参考以下对外部函数的声明:

1 C语言调用Fortran模块的声明:

extern void _stdcall SUBROUTINE(argType arg1,……);

extern float _stdcall FUNCTION(argType arg1,……);

2 C++语言调用Fortran模块的声明:

extern “C” { void _stdcall SUBROUTINE(argType arg1,……); }

extern “C” { float _stdcall FUNCTION(argType arg1,……); }

外部函数声明仅仅给调用过程提供函数的入口地置,目的是为了保证编译通过。

在链接生成可执行文件时,主调用过程根据函数名链接被调用模块,找到模块则可链接成功,有了调用规则和命名规则的修饰字进行转换,才能保证运行正常。

1.2 调用Fortran语言生成的dll模块:

如果为了调用在Fortran中已有的模块或者为了提高处理速度,可以考虑将已有程序或者算法用Fortran语言做成dll的模块,便于移植和修改,这样即使原dll模块中的算法做过修改,只要保证函数或子例行程序名字和入口参数不变,主调用过程无须进行重新修改或者编译。Dll文件的好处很多,感兴趣的读者可以参考相关计算机书籍。

Fortran程序制作dll模块的过程如下:

首先利用向导制作一个空的Visual Fortran dll项目,在生成的文件中可以看到用cDEC $ ATTRIBUTES DLLEXPORT 指令声明的函数,这个函数即为该dll输出的子程序,用户可以在外部程序中调用它来完成一定的功能。可以在一个dll文件中添加cDEC $ ATTRIBUTES DLLEXPORT指令声明多个函数、过程或要输出的数据。例如,

!在dll中声明输出函数 Fact

INTEGER*4 FUNCTION FACT(N)

!DEC$ ATTRIBUTES DLLEXPORT::FACT

INTEGER*4 N

……

END FUNCTION FACT

!在dll中声明子例行程序 ARRAYTEST

SUBROUTINE ARRAYTEST(ARR)

!DEC$ ATTRIBUTES DLLEXPORT::ARRAYTEST

REAL*4 ARR(3,7)

……

END SUBROUTINE ARRAYTEST

1.3 VC中调用IMSL数学库函数

这是混合编程比较实用的部分,笔者在使用过程中发现运用上面的改变调用规则和命名转换方法仍然无法在VC中直接调用VF的数学库,编译报错为:unresolved external call,即无法决议的外部调用。即使使用VC的编译指令#pragma comment (lib, “***.lib”)加入调用IMSL所需的三个lib文件,仍然存在未解决的外部调用错误,原因是内部调用过程不可知。

研究Compaq Visual Fortran的在线帮助可以发现,在Fortran程序中,要使用IMSL库,也需加入编译指令USE NUMERICAL_LIBRARIES来包含确切的头文件和库,这样就可以直接使用IMSL数学库中的函数。基于以上分析,我们可以定制dll,将要用到的数学函数包括到自己的模块中,然后在VC中使用,参考下面的例子:

REAL*4 FUNCTION FCBRT(A)

!Expose Function FCBRT to users of this DLL

!DEC$ ATTRIBUTES DLLEXPORT::FCBRT

USE numerical_libraries

REAL*4 A[VALUE]

!Variables

!Body of the Function

FCBRT=CBRT(A)

END FUNCTION FCBRT

注意输出函数名不要和IMSL库中的函数同名,否则生成dll时将报与库函数命名冲突!

当然用户在实际使用过程中为了简单的调用若干个数学函数,还要进行库函数的定制与打包,这是不大实际的。

以下提供一种简单的方法在VC中调用IMSL库函数,参考表一:

Static or DLL 多线程? 是否使用C调试库 使用的Fortran链接库存 使用的C链接库存

Static 否 否 dfor.lib libc.lib

Static 否 是 dfor.lib libcd.lib

Static 是 否 dformt.lib libcmt.lib

Static 是 是 dformt.lib libcmtd.lib

DLL 否 否 dfordll.lib(dforrt.dll) msvcrt.lib(msvcrt.dll)

DLL 否 是 dfordll.lib(dforrt.dll) msvcrtd.lib(msvcrtd.dll)

DLL 是 否 dformd.lib(dformd.dll) msvcrt.lib(mvcrt.dll)

DLL 是 是 dformd.lib(dformd.dll) msvcrtd.lib(msvcrtd.dll)

表一

在编程实践中,根据表一的调用依赖关系,笔者总结出了在VC工程中直接调用IMSL数学库的方法。第一,在控制台(console)应用程序中调用IMSL库函数,必须包含dfor.lib,dfconsol.lib,在MFC应用程序中调用IMSL库函数,则必须包含dformd.lib,当然上述两种情况的工程要想调用Fortran提供的数学库,如下三个库文件是基本的:

1 Imsl.lib IMSL静态库,包含了Fortran77 和 Fortran90 所有函数和子例行程序;

2 Imsls_err.lib IMSL错误处理库;

3 Imslmpistub.lib 基于多CPU的并行处理库(对于单CPU的PC机用户可省)

读者可以根据表一,结合在项目中Project菜单的Setting项中有关编译器参数对相应的库文件进行修改。

2 提供简单算例

在计算机图形学中关于曲线、曲面进行插值或拟合,将大量使用求解线性方程组。如在求B样条曲线插值问题中,要先进行反求控制顶点,然后根据B样条基求出进行插值,我们利用VC来完成界面,利用IMSL提供的数学函数完成计算。

例题:已知型值点序列Pi,i=0,1,2…,7:

P[0] P[1] P[2] P[3] P[4] P[5] P[6] P[7]

Abscissae x 8.125 8.400 9.000 9.485 9.600 9.959 10.166 10.200

Ordinates y 0.0774 0.099 0.28 0.6 0.708 1.20 1.80 2.177

求控制顶点序列。

反求B杨条曲线控制顶点的数学问题是:

D表示de Boor控制顶点,P已知型值点列和边界条件向量。

在VC中调用IMSL解线性方程组的函数LSASF/DLSASF求解,完整代码如下:

#include <iostream>

using namespace std;

#include <math.h>

#pragma comment (lib, "dfor")

#pragma comment (lib, "dfconsol")

#pragma comment (lib, "imsl")

#pragma comment (lib, "imsls_err")

//Solve a real symmetric system of linear equations with iterative refinement.

extern "C" { void _stdcall LSASF (int*, float*, int*, float*, float*); }

extern "C" { void _stdcall DLSASF (int*, double*, int*, double*, double*); }

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

{

int i,j;

int lda=8;

int n=8;

double A[8][8];

double Px[8]={ 6*8.125, 6*8.400, 6*9.000, 6*9.485, 6*9.600, 6*9.959, 6*10.166, 6*10.200 };

double Py[8]={ 6*0.0774, 6*0.099, 6*0.28, 6*0.6, 6*0.708, 6*1.20, 6*1.80, 6*2.177};

// 存放求得的解

double Dx[8],Dy[8];

for(i=0;i<8;i++)

{

for(j=0;j<8;j++)

{

if(i==j) A[i][j]=4.0;

else if(abs(i-j)==1) A[i][j]=1.0;

else A[i][j]=0.0;

}

}

A[0][0]=A[7][7]=5.0;

DLSASF(&n,&A[0][0],&lda,Px,Dx);

DLSASF(&n,&A[0][0],&lda,Py,Dy);

for(i=0;i<n;i++)

cout<<i<<"\t"<<Dx[i]<<"\t"<<Dy[i]<<endl;

return 0;

}

计算结果 Di, i=0,1,…,9

D[0]=D[1] D[2] D[3] D[4] D[5] D[6] P[7] D[8]=D[9]

Abscissae x 8.08523 8.32384 9.01941 9.59854 9.49644 10.0157 10.1948 10.201

Ordinates y 0.07852 0.07183 0.22819 0.69544 0.59008 1.19226 1.84088 2.24422

值得注意的是在声明外部函数时,Fortran 函数中的参数列表必须声明成对应C/C++参数类型的参考,即指针类型,数据类型对应关系参考表二:

Fortran Type INTEGER*1 INTEGER*2 INTEGER*4 REAL*4 REAL*8 CHRATER*1

C/C++ Type char short int, long float double unsigned char

表二

引入静态链接库或者动态链接库的方法有很多种,例程中采用的是预编译指令,读者可以参考相关编程资料。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有