我希望从我的C++代码中调用fortran例程cbesj.f,如何实现这一点?
以下是我所做的步骤:
test_cbesj.cpp:(.text+0xd6):未定义的对`cbesj_的引用(复杂*、浮点数*、长*、长*、复*、长*、长*)‘
在我的问题中,引用cbesj_子例程的正确方法是什么?谢谢!
谢谢凯西:我认为你的做法是最好的。但我还是有自己的错,为什么?我们开始:
f77 -c *.f 在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在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;
}然后,
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);谢谢罗格维布的回复!其实是个好建议。下面是更改后的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;别再犯错了。但是,出于某些原因,代码不像预期的那样工作:
./test
-1.343533039093018 -1.343533992767334
nz=0
ierr=4答案是错误的,ierr在源代码中也这样说:
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发布于 2015-12-04 17:49:43
我从cbesj (或zbesj)和相关文件中下载了网库,但由于某种原因,它们无法使用gfortran4.8 (在Linux x86_64上)。更确切地说,cbesj总是给出ierr=4,而我不能编译zbesj,因为zabs有太多的参数(但请参见下面的更新)。
因此,我放弃了使用最初的阿莫斯代码,并尝试了张扬,这也是基于阿莫斯。我简单地通过输入make (使用gfortran)来编译后者,生成libopenspecfun.a等。然后编写了下面的代码来测试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;
}并编译为
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,取消注释标记为
C MACHINE CONSTANTS FOR THE IBM PC通过这种修改,cbesj正确地使用了ierr=0;否则,它会给出ierr=4,因为某些常量默认为0。对于双精度版本,我们还需要处理用户定义的ZABS,它的定义与内部的定义冲突。Intel (ifort)识别用户定义的ZABS并成功编译它们(尽管有很多警告),而gfortran停止了语法错误的编译(假设它是固有的)。openspecfunc通过用内部的ZABS重写所有的ZABS来避免这个问题。无论如何,经过上述修改后,cbesj和zbesj都能正常工作(如预期的那样)。
更新2
事实证明,使用d1mach.f、r1mach.f和i1mach.f的BLAS版本,事情变得更加简单,因为它们自动地确定与机器相关的常量,我们不需要手动修改代码。有关详细信息,请参阅Netlib/FAQ页面。同样的技巧也适用于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 https://stackoverflow.com/questions/34082554
复制相似问题