如何从C ++调用fortran例程? [英] how to call fortran routines from C++?

查看:215
本文介绍了如何从C ++调用fortran例程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从我的C ++代码调用fortran例程cbesj.f,我该如何实现?



这里是我做的步骤:


  1. 从netlib amos网页下载cbesj.f plus依赖项, http://www.netlib.org/cgi-bin/netlibfiles.pl?filename=/amos/cbesj.f



  2. g ++ -c * .c



    ar cr libmydemo.a * .o


  3. [test_cbesj.cpp] [1]和
    [mydemo.h] [2]用于以这种方式调用子例程,



    g ++ test_cbesj.cpp -lf2c -lm -L。 -lmydemo
    它返回错误:





test_cbesj.cpp :(。 text + 0xd6):未定义对`cbesj_(complex *,float *,long *,long *,complex *,long *,long *)'的引用



b $ b

在我的问题中引用cbesj_子例程的正确方法是什么?谢谢!



感谢您的帮助:
我认为您的方法是最好的。但我还是设定了错,为什么?我们去:

  f77 -c * .f 

in modemo.h

  //档案mydemo.h 
#ifndef MYDEMO_H
#define MYDEMO_H
#include< stdio.h> / *输入和输出的标准库* /
#includef2c.h

externCint cacai_(complex * z__,real * fnu,integer * kode, mr,integer * n,complex * y,integer * nz,real * rl,real * tol,real * el \
im,real * alim);
externCint cairy_(complex * z__,integer * id,integer * kode,complex * ai,integer * nz,integer * ierr);
externCint casyi_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,real * rl,real * tol,real *
* alim);
externCint cbesj_(complex * z__,real * fnu,integer * kode,integer * n,complex * cy,integer * nz,integer * ierr)
externCint cbinu_(complex * z__,real * fnu,integer * kode,integer * n,complex * cy,integer * nz,real * rl,real * fnul,real * tol,real * el \
im,real * alim);
externCint cbknu_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,real * tol,real * elim,real * alim)
externCint cbuni_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,integer * nui,integer * nlast,real * fnul,\
real * tol,real * elim,real * alim);
externCint ckscl_(complex * zr,real * fnu,integer * n,complex * y,integer * nz,complex * rz,real * ascle,real * tol,real * elim)
externCint cmlri_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,real * tol)
externCint crati_(complex * z__,real * fnu,integer * n,complex * cy,real * tol)
externCint cs1s2_(complex * zr,complex * s1,complex * s2,integer * nz,real * ascle,real * alim,integer * iuf);
externCint cseri_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,real * tol,real * elim,real * alim)
externCint cshch_(complex * z__,complex * csh,complex * cch);
externCint cuchk_(complex * y,integer * nz,real * ascle,real * tol);
externCint cunhj_(complex * z__,real * fnu,integer * ipmtr,real * tol,complex * phi,complex * arg,complex * zeta1,complex * zeta2,complex\
* asum,complex * bsum);
externCint cuni1_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,integer * nlast,real * fnul,real * tol \
,real * elim,real * alim);
externCint cuni2_(complex * z__,real * fnu,integer * kode,integer * n,complex * y,integer * nz,integer * nlast,real * fnul,real * tol \ $ $ b,real * elim,real * alim);
externCint cunik_(complex * zr,real * fnu,integer * ikflg,integer * ipmtr,real * tol,integer * init,complex * phi,complex * zeta1,complex\
* zeta2,complex * sum,complex * cwrk);
externCint cuoik_(complex * z__,real * fnu,integer * kode,integer * ikflg,integer * n,complex * y,integer * nuf,real * tol,real * elim,re \\
al * alim);
externCint cwrsk_(complex * zr,real * fnu,integer * kode,integer * n,complex * y,integer * nz,complex * cw,real * tol,real * elim,real * a \
lim);
externCreal gamln_(real * z__,integer * ierr);
externCinteger i1mach_(integer * i__);
externCreal r1mach_(integer * i__);
externCint xerror_(char * mess,integer * nmess,integer * l1,integer * l2,ftnlen mess_len);
#endif

在test_cbesj.cpp中,

  #includemydemo.h
#includef2c.h
#include< math.h>
#include< iostream>
#include< stdio.h>
#include< assert.h>
using namespace std;
int main(void)
{
// double x = 86840 .;
// int nu = 46431,j,err;
complex * z,z__;
z __。r = 3.0; z __。i = 2.0; z =& z__;
cout<< z→r < '\t'<< z - > i< endl;
real * fnu; float fnu__ = 3.0; fnu =& fnu__;
integer * kode; long int kode __ = 1; kode =& kode__;
integer * n; long int n __ = 1; n =& n__;
complex * cy;
integer * nz;
integer * ierr;
cbesj_(z,fnu,kode,n,cy,nz,ierr);
cout<< cy-> r < '\t'<< cy-> i< endl;

return 0;
}

然后,

  g ++ -c -g test_cbesj.cpp 
g ++ -o test * .o -lg2c
./test
3 2
分段故障(核心转储)
gdb test
GNU gdb(Ubuntu / Linaro 7.4-2012.04-0ubuntu2.1)7.4-2012.04
版权所有(C)2012自由软件基金会,
许可GPLv3 +:GNU GPL版本3或更高版本< http://gnu.org/licenses/gpl.html>
这是免费软件:您可以自由更改和重新分配。
在法律允许的范围内,没有任何保证。有关详细信息,请键入显示复制
和显示保修。
此GDB配置为i686-linux-gnu。
有关错误报告说明,请参阅:
< http://bugs.launchpad.net/gdb-linaro/> ...
从/ media / Downloads / amos中读取符号-4 / test ... done。
(gdb)run
启动程序:/ media / Downloads / amos-4 / test
3 2

程序接收信号SIGSEGV,分段故障。
0x0804b355 in cbesj_()
(gdb)frame 0
#0 0x0804b355 in cbesj_()
(gdb)frame 1
#1 0x0805a3ca in main test_cbesj.cpp:21
21 cbesj_(z,fnu,kode,n,cy,nz,ierr);

感谢roygvib的回复!好建议。这里是改变的test_cbesj.cpp:

  complex z,cy; 
float fnu;
long int kode,n,nz,ierr;

z.r = 3.0; z.i = 2.0;
fnu = 3.0;
n = 1; kode = 1;
cout.precision(16);
cbesj_(& z,& fnu,& kode,& n,& cy,& nz,& ierr);
cout<< cy.r < '\t'<< cy.i < endl;
cout<< nz =<< nz < endl;
cout<< ierr =< ierr<< Lendl;

没有更多seg故障。但出于某些原因,代码无法按预期工作:

  ./ test 
-1.343533039093018 -1.343533992767334
nz = 0
ierr = 4

所以从源代码:

  C NZ  - 由于底层组件设置为零的组件数,
C NZ = 0,正常返回
C NZ.GT.0,CY设置为零的最后一个NZ组件
由于下溢,CY(I)= CMPLX(0.0,0.0),
CI = N-NZ + 1,...,N
C IERR - 错误标志
C IERR = 0,正常返回 - 计算完成
C IERR = 1,输入错误 - 无计算
C IERR = 2,OVERFLOW - NO COMPUTATION,AIMAG(Z)
C TOO LARGE ON KODE = 1
C IERR = 3,CABS(Z)或FNU + N-1 LARGE - COMPUTATION DONE
C
C C $ C $ B C $ C $ B C code code $ C $ - NO COMPUTA-
由于SIGNIFI-
的完全损失而导致的损失
C $因为减少
C IERR = 5,错误 - 无计算
算法终止条件不MET


解决方案

我下载了 cbesj (或 zbesj )和相关文件 netlib ,但由于某种原因,他们没有使用gfortran4.8(在Linux x86_64)。更确切地说, cbesj 总是给出 ierr = 4 ,而我不能编译 zbesj 因为 zabs 有太多的参数(但请参阅下面的更新)。






因此,我放弃了原来的AMOS代码,并尝试 openspecfun 也基于AMOS。我编译后简单地通过键入 make (与gfortran),生成libopenspecfun.a等。然后我做了以下代码测试 zbesj

  #include< cstdio> 

externC{
void zbesj_(double * zr,double * zi,double * fnu,int * kode,int * n,
double * Jr,double * Ji,int * nz,int * ierr);
}

int main()
{
int n,nz,ierr,kode;
double fnu,zr,zi,Jr,Ji;

fnu = 2.5;
zr = 1.0; zi = 2.0;
n = 1; kode = 1;

zbesj_(& zr,& zi,& fnu,& kode,& n,& Jr,& Ji,& nz,& ierr);

printf(fnu =%20.15f \\\
,fnu);
printf(z =%20.15f%20.15f \\\
,zr,zi);
printf(J =%20.15f%20.15f \\\
,Jr,Ji);
printf(nz,ierr =%d%d \\\
,nz,ierr);

return 0;
}

并编译为

  g ++ test_zbesj.cpp libopenspecfun.a -lgfortran 

给出

  fnu = 2.500000000000000 
z = 1.000000000000000 2.000000000000000
J = -0.394517225893988 0.297628229902939
nz, ierr = 0 0

因为这个网站说答案是 -0.394517 ... + 0.297628 ... i zbesj 的结果似乎是正确的。






[更新]



通过仔细阅读原始代码并与 openspecfun ,发现用户需要取消注释 i1mach.f r1mach.f 的适当部分 d1mach.f ),具体取决于机器环境。对于Linux x86_64,取消注释标有

的部分似乎已经足够了。

  IBM PC的机器持续运行

通过此修改, cbesj > ierr = 0 ;否则它给出 ierr = 4 ,因为一些常数缺省为 0 。对于双精度版本,我们还需要处理用户定义的 ZABS ,其定义与内在冲突。 Intel Fortran( ifort )识别用户定义的 ZABS ,并成功编译它们(虽然有很多警告),而gfortran停止编译语法错误(假设它是内在的)。 openspecfunc 通过使用内部函数重写所有 ZABS 来避免此问题。无论如何,与上述修改 cbesj zbesj 工作正常(如预期)。






[更新2]



事实证明,使用BLAS版本 d1mach.f r1mach.f i1mach.f 变得更简单,因为他们自动确定机器相关的常数,我们不需要手动修改代码。有关详情,请参阅 Netlib /常见问题页面。同样的窍门也适用于SLATEC(例如,此页面)。



  wget http://www.netlib.org/blas/i1mach.f 
wget http://www.netlib .org / blas / r1mach.f
wget http://www.netlib.org/blas/d1mach.f


I wish to call fortran routine cbesj.f from my C++ code and how do I achieve this?

Here are steps I have done:

  1. Download cbesj.f plus dependencies from netlib amos webpage, http://www.netlib.org/cgi-bin/netlibfiles.pl?filename=/amos/cbesj.f

  2. In the source dir,

    f2c -C++PR *.f

    g++ -c *.c

    ar cr libmydemo.a *.o

  3. [test_cbesj.cpp][1] and [mydemo.h][2] are used to call the subroutine in this way,

    g++ test_cbesj.cpp -lf2c -lm -L. -lmydemo it returns bug:

test_cbesj.cpp:(.text+0xd6): undefined reference to `cbesj_(complex*, float*, long*, long*, complex*, long*, long*)'

What shall be the proper way to refer to cbesj_ subroutine in my problem? Thanks!

Thanks for casey: I think your approach is the best. But I still have set fault, why? Here we go:

f77 -c *.f    

in modemo.h

//File mydemo.h                                                                                                                              
#ifndef MYDEMO_H
#define MYDEMO_H
#include <stdio.h>      /* Standard Library of Input and Output */
#include "f2c.h"

extern"C" int cacai_(complex *z__, real *fnu, integer *kode, integer *mr,         integer *n, complex *y, integer *nz, real *rl, real *tol, real *el\
im, real *alim);
extern"C" int cairy_(complex *z__, integer *id, integer *kode, complex *ai,         integer *nz, integer *ierr);
extern"C" int casyi_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, real *rl, real *tol, real *elim, real     \
  *alim);
extern"C" int cbesj_(complex *z__, real *fnu, integer *kode, integer *n,     complex *cy, integer *nz, integer *ierr);
extern"C" int cbinu_(complex *z__, real *fnu, integer *kode, integer *n,     complex *cy, integer *nz, real *rl, real *fnul, real *tol, real *el\
im, real *alim);
extern"C" int cbknu_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, real *tol, real *elim, real *alim);
extern"C" int cbuni_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, integer *nui, integer *nlast, real *fnul, \
real *tol, real *elim, real *alim);
extern"C" int ckscl_(complex *zr, real *fnu, integer *n, complex *y, integer *nz, complex *rz, real *ascle, real *tol, real *elim);
extern"C" int cmlri_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, real *tol);
extern"C" int crati_(complex *z__, real *fnu, integer *n, complex *cy, real *tol);
extern"C" int cs1s2_(complex *zr, complex *s1, complex *s2, integer *nz, real *ascle, real *alim, integer *iuf);
extern"C" int cseri_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, real *tol, real *elim, real *alim);
extern"C" int cshch_(complex *z__, complex *csh, complex *cch);
extern"C" int cuchk_(complex *y, integer *nz, real *ascle, real *tol);
extern"C" int cunhj_(complex *z__, real *fnu, integer *ipmtr, real *tol, complex *phi, complex *arg, complex *zeta1, complex *zeta2, complex\
 *asum, complex *bsum);
extern"C" int cuni1_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, integer *nlast, real *fnul, real *tol     \
  , real *elim, real *alim);
extern"C" int cuni2_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, integer *nlast, real *fnul, real *tol     \
  , real *elim, real *alim);
extern"C" int cunik_(complex *zr, real *fnu, integer *ikflg, integer *ipmtr, real *tol, integer *init, complex *phi, complex *zeta1, complex\
 *zeta2, complex *sum, complex *cwrk);
extern"C" int cuoik_(complex *z__, real *fnu, integer *kode, integer *ikflg,     integer *n, complex *y, integer *nuf, real *tol, real *elim, re\
al *alim);
extern"C" int cwrsk_(complex *zr, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, complex *cw, real *tol, real *elim, real *a\
lim);
extern"C" real gamln_(real *z__, integer *ierr);
extern"C" integer i1mach_(integer *i__);
extern"C" real r1mach_(integer *i__);
extern"C" int xerror_(char *mess, integer *nmess, integer *l1, integer *l2,     ftnlen mess_len);
    #endif

in test_cbesj.cpp,

#include "mydemo.h"
#include "f2c.h"
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <assert.h>
using namespace std;
int main(void)
{
  //  double x=86840.;                                                                                                                       
  //int nu=46431,j, err;                                                                                                                     
  complex *z,z__;
  z__.r = 3.0;z__.i = 2.0;z = &z__;
  cout << z->r << '\t' << z->i << endl;
  real *fnu;float fnu__ = 3.0;fnu = &fnu__;
  integer *kode ;long int kode__=1;kode=&kode__;
  integer *n    ;long int n__=1;n=&n__;
  complex *cy;
  integer *nz;
  integer *ierr;
  cbesj_(z, fnu, kode, n, cy, nz, ierr);
  cout << cy->r << '\t' << cy->i << endl;

  return 0;
}

Then,

g++ -c -g test_cbesj.cpp
g++ -o test *.o -lg2c
./test
3   2
Segmentation fault (core dumped)
gdb test 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /media/Downloads/amos-4/test...done.
(gdb) run
Starting program: /media/Downloads/amos-4/test 
3   2

Program received signal SIGSEGV, Segmentation fault.
0x0804b355 in cbesj_ ()
(gdb) frame 0
#0  0x0804b355 in cbesj_ ()
(gdb) frame 1
#1  0x0805a3ca in main () at test_cbesj.cpp:21
21    cbesj_(z, fnu, kode, n, cy, nz, ierr);

Thanks for roygvib's reply! Good suggestions actually. Here is the changed test_cbesj.cpp:

complex z, cy;
  float fnu;
  long int kode, n, nz, ierr;

  z.r = 3.0; z.i = 2.0;
  fnu = 3.0;
  n = 1; kode = 1;
  cout.precision(16);
  cbesj_( &z, &fnu, &kode, &n, &cy, &nz, &ierr );
  cout << cy.r << '\t' << cy.i << endl;
  cout << "nz=" << nz << endl;
  cout << "ierr=" << ierr << Lendl;

No more seg fault. But out of some reasons, the code does not work as expected:

./test
-1.343533039093018  -1.343533992767334
nz=0
ierr=4

and answers are wrong and ierr also says so from the source code:

C           NZ     - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW,
C                    NZ= 0   , NORMAL RETURN
C                    NZ.GT.0 , LAST NZ COMPONENTS OF CY SET TO ZERO
C                              DUE TO UNDERFLOW, CY(I)=CMPLX(0.0,0.0),
C                              I = N-NZ+1,...,N
C           IERR   - ERROR FLAG
C                    IERR=0, NORMAL RETURN - COMPUTATION COMPLETED
C                    IERR=1, INPUT ERROR   - NO COMPUTATION
C                    IERR=2, OVERFLOW      - NO COMPUTATION, AIMAG(Z)
C                            TOO LARGE ON KODE=1
C                    IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE
C                            BUT LOSSES OF SIGNIFCANCE BY ARGUMENT
C                            REDUCTION PRODUCE LESS THAN HALF OF MACHINE
C                            ACCURACY
C                    IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA-
C                            TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI-
C                            CANCE BY ARGUMENT REDUCTION
C                    IERR=5, ERROR              - NO COMPUTATION,
C                            ALGORITHM TERMINATION CONDITION NOT MET

解决方案

I downloaded cbesj (or zbesj) and related files from netlib, but for some reason they did not work with gfortran4.8 (on Linux x86_64). More precisely, cbesj always gives ierr=4, while I could not compile zbesj because zabs has too many arguments (but please see the update below).


So I gave up using the original AMOS codes and tried openspecfun that is also based on AMOS. I compiled the latter simply by typing make (with gfortran), which generated libopenspecfun.a etc. Then I made the following code to test zbesj:

#include <cstdio>

extern "C" {
    void zbesj_( double *zr, double *zi, double *fnu, int *kode, int *n,
                 double *Jr, double *Ji, int *nz, int *ierr );
}

int main()
{
    int    n, nz, ierr, kode;
    double fnu, zr, zi, Jr, Ji;

    fnu = 2.5;
    zr = 1.0; zi = 2.0;
    n = 1; kode = 1;

    zbesj_( &zr, &zi, &fnu, &kode, &n, &Jr, &Ji, &nz, &ierr );

    printf( "fnu = %20.15f\n", fnu );
    printf( "z   = %20.15f %20.15f\n", zr, zi );
    printf( "J   = %20.15f %20.15f\n", Jr, Ji );
    printf( "nz, ierr = %d %d\n", nz, ierr );

    return 0;
}

and compiled as

g++ test_zbesj.cpp libopenspecfun.a -lgfortran

which gives

fnu =    2.500000000000000
z   =    1.000000000000000    2.000000000000000
J   =   -0.394517225893988    0.297628229902939
nz, ierr = 0 0

Because this site says the answer is -0.394517...+ 0.297628...i, the result of zbesj seems correct.


[Update]

By reading the original code more carefully and also comparing with openspecfun, it was found that the user needs to uncomment appropriate sections of i1mach.f and r1mach.f (or d1mach.f) depending on the machine environment. For Linux x86_64, it seems sufficient to uncomment the section tagged with

C     MACHINE CONSTANTS FOR THE IBM PC

With this modification, the cbesj worked correctly with ierr=0; otherwise it gives ierr=4 because some constants default to 0. For the double-precision version, we also need to deal with the user-defined ZABS, whose definition conflicts with the intrinsic one. The Intel Fortran (ifort) recognizes the user-defined ZABS as such and compiles them successfully (although with a lot of warnings), while gfortran stops compiling with syntax error (assuming it to be the intrinsic one). openspecfunc avoids this problem by rewriting all the ZABS with the intrinsic one. Anyway, with the above modifications both cbesj and zbesj worked correctly (as expected).


[Update 2]

It turned out that using the BLAS version of d1mach.f, r1mach.f, and i1mach.f, things become even simpler because they determine machine-dependent constants automatically and we don't need to modify the codes manually. Please see the Netlib/FAQ page for details. The same trick applies to SLATEC also (e.g., this page).

wget http://www.netlib.org/blas/i1mach.f 
wget http://www.netlib.org/blas/r1mach.f
wget http://www.netlib.org/blas/d1mach.f 

这篇关于如何从C ++调用fortran例程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆