Fortran是世界上第一个计算机高级语言,它属于面向过程的语言,其在科学计算领域具有很大优势,但是它在图像用户界面设计方面表现出劣势,而且现在越来越多的项目和程序需要多种语言的混合编写,所以掌握多种语言的编写以及它们之间的连接对于以后的程序编写具有很方便的优势。
在本文中我使用Java语言来调用Fortran的动态链接库:
在此我们先了解一些基础知识,FORTRAN和Java中数据类型表示:
FORTRAN | Java |
---|---|
integer*1 | byte |
integer*2 | short |
integer*4(默认) | int(默认) |
integer*8 | long |
real*4(默认) | float |
real*8 | double(默认) |
character (len=?) | String |
Fortran的编译器现在使用比较多的是VS+IVF,我们使用VS产生动态链接库。
在VS中新建一个项目,选择Library中的第一项,建立后,新建一个f90文件,然后编写一个子例行程序和子函数程序:
Subroutine rectangle(x,y,area,perimeter)
!DEC$ ATTRIBUTES DLLEXPORT :: rectangle
Implicit none
real ( kind = 8 ) :: x,y
real ( kind = 8 ) :: area, perimeter
area = x*y
perimeter = 2.0*(x+y)
end Subroutine
!-------------------------------------------c
Function ave(a1,a2,a3,a4)
!DEC$ ATTRIBUTES DLLEXPORT :: ave
Implicit none
real ( kind = 8 ) :: ave
real ( kind = 8 ) :: a1,a2,a3,a4
ave = (a1+a2+a3+a4)/4.0
end function
!-----------------------------------------c
如上述程序,编写了一个子例行程序和一个子函数程序,分别演示子例行程序、子函数在Java中的调用方式,这两个子程序在一个文件中,会被统一编译成一个DLL文件:
rectangle程序输入长X和宽Y,用来求取一个长方形的面积和周长
!DEC$ ATTRIBUTES DLLEXPORT :: rectangle
这个语言必须有,是VS使用的DLL接口,供外部程序调用。
ave程序用来求取四个数的平均数,需要注意的是,要使自己编译的DLL文件不依赖其他系统或者基础DLL文件,需要在VS上有如下设置:
之后编译产生一个DLL文件
现在使用Java编写调用程序,需要用到jna.jar和jna-platform.jar两个包,网上有,可以自行下载。
首先将两个jar包导入项目中,然后写一个接口:
package cn.CSDN.demo01;
import com.sun.jna.Library;
import com.sun.jna.ptr.ByReference;
public interface DLL extends Library{
//不管FORTRAN中的子程序名字是否大写或者部分大写,这里必须全部大写,子例行程序没有返回值,写void
public abstract void RECTANGLE(ByReference x,ByReference y ,ByReference area, ByReference perimeter);
//子函数程序是有返回值的,所以对于子函数必须写返回值,返回值与数值类型相同
public abstract double AVE(ByReference a1,ByReference a2,ByReference a3,ByReference a4);
}
这里必须切记不管FORTRAN中的子程序名字是否大写或者部分大写,这里子程序的名称必须全部大写,子例行程序没有返回值,写void,而子函数程序是有返回值的,所以对于子函数必须写返回值,返回值与数值类型相同,对于数值类型,在Java中先定义为ByReference,而字符串类型定义为String。
接下来写一个调用类:
public static void main(String[] args) {
DLL dll = (DLL) Native.loadLibrary("C:\\Users\\Administrator\\Desktop\\Java\\geo\\CSDN.dll", DLL.class);
DoubleByReference x = new DoubleByReference(10.0);
DoubleByReference y = new DoubleByReference(15.0);
//area和perimeter虽然是返回值,但是也要赋初值,可以随便赋值,一般赋值0
DoubleByReference area = new DoubleByReference(0);
DoubleByReference perimeter = new DoubleByReference(0);
dll.RECTANGLE(x, y, area, perimeter);
System.out.println("面积为"+area.getValue());
System.out.println("周长为"+perimeter.getValue());
上面的代码就是调用 Subroutine rectangle(x,y,area,perimeter)的程序,其中那个dll文件的绝对路径中的单斜线必须改为双斜线,和Java中的正则化表示有关,注意加载文件的表达式:
接口名 变量 = (接口名)Native.loadLibrary(“绝对位置的DLL文件”,接口名.class)
该程序结果如下:
DoubleByReference a1 =new DoubleByReference(5.0);
DoubleByReference a2 =new DoubleByReference(7.0);
DoubleByReference a3 =new DoubleByReference(9.0);
DoubleByReference a4 =new DoubleByReference(11.0);
//对于子函数,用一个同类型的变量接收子函数的值
double result = dll.AVE(a1, a2, a3, a4);
System.out.println("平均值为"+result);
上述为子函数ave(a1,a2,a3,a4)的调用,结果正确。
完整的程序为:
package cn.CSDN.demo01;
import com.sun.jna.Native;
import com.sun.jna.ptr.DoubleByReference;
public class CSDNTest {
public static void main(String[] args) {
DLL dll = (DLL) Native.loadLibrary("C:\\Users\\Administrator\\Desktop\\Java\\geo\\CSDN.dll", DLL.class);
DoubleByReference x = new DoubleByReference(10.0);
DoubleByReference y = new DoubleByReference(15.0);
//area和perimeter虽然是返回值,但是也要赋初值,可以随便赋值,一般赋值0
DoubleByReference area = new DoubleByReference(0);
DoubleByReference perimeter = new DoubleByReference(0);
dll.RECTANGLE(x, y, area, perimeter);
System.out.println("面积为"+area.getValue());
System.out.println("周长为"+perimeter.getValue());
DoubleByReference a1 =new DoubleByReference(5.0);
DoubleByReference a2 =new DoubleByReference(7.0);
DoubleByReference a3 =new DoubleByReference(9.0);
DoubleByReference a4 =new DoubleByReference(11.0);
//对于子函数,用一个同类型的变量接收子函数的值
double result = dll.AVE(a1, a2, a3, a4);
System.out.println("平均值为"+result);
}
}
有关java和fortran混编的字符串部分的详解,可以关注第二部分。