将C++数组传递给Fortran子例程会导致nan值出现在结果中
Passing C++ array to Fortran subroutine causes nan values to appear in result
我正在尝试使用C++应用程序中的Fortran代码。具体来说,我试图与SLATEC的drc3jj.f接口。然而,Fortran子程序返回一个数组,其大小取决于传递给函数的参数。
如果数组的大小是1,那么我打印的C++数组包含适当的值。但是,如果此大小大于1,则C++数组包含NaN,其中应该有输出值。
下面是我使用的代码。这只是将Fortran子程序链接到C++应用程序。
#ifndef FORTRANLINKAGE_H
#define FORTRANLINKAGE_H
extern "C"
{
extern void drc3jj_(double*,double*,double*,double*,double*,
double*,double [],int*,int*);
}
#endif // FORTRANLINKAGE_H
肉在下面。实际上,我们从C++调用Fortran子程序并打印输出:
#include "fortranLinkage.h"
#include <iostream>
#include <stdlib.h>
using namespace std;
void wigner3j(double l2, double l3, double m2, double m3, double coeff [])
{
double l1min,l1max;
int ierr,size(3);
drc3jj_(&l2,&l3,&m2,&m3,&l1min,&l1max,coeff,&size,&ierr);
cout << "Min: " << l1min << "t Max: " << l1max << "t Err: " << ierr << endl;
}
int main(int argc, char const *argv[])
{
int l1(atoi(argv[1])),l2(atoi(argv[2])),m2(atoi(argv[3])),m3(atoi(argv[4]));
double coeff [3];
wigner3j(l1,l2,m2,m3,coeff);
for (int i=0;i<3;i++)
{
cout << coeff[i] << endl;
}
return 0;
}
如果我们用./myProgram 2 8 2 8
调用程序,它会正确地输出1/sqrt(21)。然而,如果我们尝试./myProgram 2 8 2 7
,其中数组的大小实际上是2,我们会得到这样的结果:
Min: 9 Max: 10 Err: 0
-nan
-nan
2.08175e-317
NaN实际上有正确的符号。
无论如何,有没有其他(正确的)方法可以将C++数组传递给Fortran?这就是问题所在吗?
问题不在于C++和Fortran之间的接口,而在于过时的Fortran实现。文件drc3jj.f是SLATEC库的一部分,该库具有返回常量的实用函数,这些常量取决于运行该库的机器(机器常量)。它们在文件d1mach.f
、i1mach.f
和r1mach.f
中定义。
但是,从Fortran 95开始,就存在一些内部函数,如huge()
、tiny()
、spacing()
和epsilon()
,它们保证为任何机器返回正确的值。
因此,解决方案是在drc3jj()
子例程中删除对d1mach(int)
的任何引用,并用适当的内部函数替换它们。
此外,直接链接到Fortran子程序总是很棘手,因为它依赖于编译器;更好的方法是在fortran90中使用iso_c_binding
以一种类型安全的方式为您定义到C的接口:
!wrapper.f90:
subroutine drc3jj_wrap(l2, l3, m2, m3, l1min, l1max, thrcof, ndim, ier) bind(C)
use iso_c_binding
implicit none
real(c_double), value, intent(in) :: l2, l3, m2, m3
real(c_double), intent(out) :: l1min, l1max
real(c_double), dimension(ndim), intent(out):: thrcof
integer (c_int), value, intent(in) :: ndim
integer (c_int), intent(out) :: ier
interface
SUBROUTINE DRC3JJ (L2, L3, M2, M3, L1MIN, L1MAX, THRCOF, NDIM, IER)
INTEGER NDIM, IER
DOUBLE PRECISION L2, L3, M2, M3, L1MIN, L1MAX, THRCOF(NDIM)
end SUBROUTINE DRC3JJ
end interface
call DRC3JJ(l2, l3, m2, m3, l1min, l1max, thrcof, ndim, ier)
end subroutine drc3jj_wrap
和
// fortranLinkage2.h
#ifndef FORTRANLINKAGE_H
#define FORTRANLINKAGE_H
extern "C"
{
extern void drc3jj_wrap(double l2, double l3, double m2, double m3,
double *l1max, double *l2max, double *thrcof,
int ndim, int *ier);
}
#endif // FORTRANLINKAGE_H
然后你打电话给
void wigner3j(double l2, double l3, double m2, double m3, double coeff [])
{
double l1min,l1max;
int ierr,size(3);
drc3jj_wrap(l2,l3,m2,m3,&l1min,&l1max,coeff,size,&ierr);
cout << "Min: " << l1min << "t Max: " << l1max << "t Err: " << ierr << endl;
}
编译和运行提供
$ g++ -c foo2.cc
$ gfortran -c wrapper.f90
$ gfortran -c drc3jj.f
$ g++ -o foo2 foo2.o wrapper.o drc3jj.o -lgfortran
$ ./foo2 2 8 2 8
Min: 10 Max: 10 Err: 0
0.218218
2.07738e-317
0
gpc-f103n084-$ ./foo2 2 8 2 7
Min: 9 Max: 10 Err: 0
-0.102598
-0.19518
0
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- valgrind-hellgrind与泄漏检查的结果不同
- 用C++20 fmt限制结果的总大小
- 如何返回一个类的两个对象相加的结果
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 序列化,没有库的整数,得到奇怪的结果
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 在更改for循环的第三部分后,未使用for循环结果
- 使用++运算符会导致意外的结果
- 为什么 acos() 在使用点积的结果时会导致"nan(ind)"?
- 为什么需要 FPU 重置以防止 NaN 结果传播到下一个计算结果?
- 从文本文件中读取并使用 sizeof 结果计算整数的数量到 nan
- 双倍和NaN比较的结果是什么
- 着色器中实现双精度cos()的结果是NaN,但在CPU上运行良好.出了什么问题
- 将C++数组传递给Fortran子例程会导致nan值出现在结果中
- 矩阵乘法的结果是'nan'
- 将数字与NaN进行比较的结果是什么
- C++ POW(X,Y) X 负双精度和 Y 负双精度,结果给出 nan