Robert L. Parker and Philip B. Stark 在 Fortran 中有一个代码:
语言
subroutine bv(key, m, n, a, b, bl, bu, x, w, act, zz, istate, loopA)
implicit double precision (a-h, o-z)
! x is an unknown n-vector
! a is a given m by n matrix
! b is a given m-vector
! bl is a given n-vector of lower bounds on the components of x.
! bu is a given n-vector of upper bounds on the components of x.
! key = 0
! ---Output parameters:
! x the solution vector.
! w(1) the minimum 2-norm || a.x-b ||.
! istate vector indicating which components of x are active
! loopA number of iterations taken in the main loop, Loop A.
! ---Working arrays:
! w dimension n. act dimension m*(mm+2). mm=min(m,n).
! zz dimension m. istate dimension n+1.
我正在尝试从 c# 中的 dll 中调用该函数,例如:
C#
class Program
{
[DllImport("bv.dll", CallingConvention = CallingConvention.StdCall )]
public static extern void bvls(
int key, //key = 0, the subroutine solves the problem from scratch. If key > 0 the routine initializes using the user's guess about which components of x are `active'
int m,
int n,
double[] a, // m by n matrix
double[] b, // m-vector
double[] bl, //n-vector of lower bounds on the components of x.
double[] bu, //n-vector of upper bounds on the components of x.
ref double[] x, //unknown n-vector
//Working arrays:
ref double[] w, //dimension n
double[] act, //dimension m*(mm+2). mm=min(m,n).
double[] zz, //dimension m
ref double[] istate, //dimension n+1.
ref int loopA // number of iterations taken in the main loop, Loop A.
);
static void Main(string[] args)
{
double[] a = new double[3 * 3] { //M*N
1.0, 10.0, 10.0,
2.0, 18.0, 16.0,
1.8, 69.0, 16.0
};
double[] b = new double[3] { //LDB*NRHS
4.3, 6.8, 1.0,
};
double[] bl = new double[3];
double[] bu = new double[3];
double[] x = new double[3];
double[] w = new double[3];
double[] act = new double[3* 5]; //dimension m*(mm+2). mm=min(m,n).
double[] zz = new double[3];
double[] istate = new double[4];
int loopA =0;
Program.bv(0, 3, 3, a, b, bl, bu, ref x, ref w, act, zz, ref istate, ref loopA);
for (int j = 0; j < 3; j++)
Console.Write(" \t" + x[j]);
}
}
但是当执行我得到的代码时
EntryPointNotFoundException: Entry point was not found. in 'bv' on file 'bv.dll'.
myProject.Program.bv(Int32 key, Int32 m, Int32 n, Double[] a, Double[] b, Double[] bl, Double[] bu, Double[]& x, Double[]& w, Double[] act, Double[] zz, Double[]& istate, Int32& loopA)
基本上我有两个问题, 如何让它工作?和其他问题,我定义函数的方式是否正确
[DllImport("bv.dll", CallingConvention = CallingConvention.StdCall )]
public static extern void bvls(...)
基于fortran代码的例程信息?
使用 dependency walker 时我得到:
我怀疑 dll 不正确并且没有例程,有没有办法检查 dll 是否以正确的方式生成?
更新
在尝试 ILSpy 之后,我得到了以下信息,这似乎不正确,请问您能否建议如何正确生成 dll 文件?ILSpy 是否告诉我 bvlsFortran 是我应该使用的函数?我试过了,但无法让它工作
最佳答案
在 FORTRAN
中试试这个:
MODULE CALCBV
INTEGER, PARAMETER :: sp = SELECTED_REAL_KIND(p=6,r=37) ! IEEE Single Precision (32-bit)
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(p=15,r=307) ! IEEE Double Precision (64-bit)
CONTAINS
subroutine bv(key, m, n, a, b, bl, bu, x, w, act, zz, istate, loopA)
IMPLICIT NONE
!DEC$ ATTRIBUTES DLLEXPORT :: bv
!DEC$ ATTRIBUTES ALIAS:'BV' :: bv
!DEC$ ATTRIBUTES VALUE :: key, m, n
INTEGER, INTENT(IN) :: key, m, n
REAL(dp), INTENT(IN) :: a(m,n), b(m), bl(n), bu(n)
REAL(dp), INTENT(OUT) :: x(n), w(n)
REAL(dp), INTENT(IN) :: act(m,MIN(m,n)+2), zz(m)
INTEGER, INTENT(OUT) :: istate(n+1)
INTEGER, INTENT(OUT) :: loopA
! DO CALC HERE
end subroutine
END MODULE
然后从 C#
调用它:
[DllImport("bv.dll", CallingConvention=CallingConvention.Cdecl, EntryPoint="BV")]
static extern void bvls(
int key, //key = 0, the subroutine solves the problem from scratch. If key > 0 the routine initializes using the user's guess about which components of x are `active'
int m,
int n,
double[] a, // m by n matrix
double[] b, // m-vector
double[] bl, //n-vector of lower bounds on the components of x.
double[] bu, //n-vector of upper bounds on the components of x.
double[] x, //unknown n-vector
//Working arrays:
double[] w, //dimension n
double[] act, //dimension m*(mm+2). mm=min(m,n).
double[] zz, //dimension m
int[] istate, //dimension n+1.
ref int loopA // number of iterations taken in the main loop, Loop A.
);
// Test code
static void BVTEST()
{
int key=0, n=2, m=3;
double[] a= { 1.0, 2.0, 3.0, 4.0, 5.0 };
double[] b= { 10.0, 20.0, 30.0 };
double[] bl= { 0.0, 1.0 };
double[] bu= { 1.0, 2.0 };
double[] x=new double[n];
double[] w=new double[n];
double[] act=new double[m*Math.Min(m, n)+2];
double[] zz=new double[m];
int[] istate=new int[n+1];
int loopA = 0;
// Call Fortran .dll
bvls(key, m, n, a, b, bl, bu, x, w, act, zz, istate, ref loopA);
}
记住数组已经是引用类型(默认)所以它们不需要 ref
关键字。输出值像 loopA
一样需要它,但是通过值参数传递需要 VALUE
属性声明以避免用 ref
传递它们,就像键
,m
,n
。您可能需要将 act
的大小固定为更大的值,因为在此之后我在参数中遇到了一些内存损坏。
这篇文章应该会让您朝着正确的方向前进。请记住始终将 Cdecl
与 FORTRAN .dll 一起使用并且始终 使用implicit none
声明。编译为 x86
和 Win32
并且不使用 AnyCPU
。使用 ALIAS
属性声明您的导出以便显示。
关于c# - Fortran Dll导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22134259/