如何检查 Fortran real 是否与 C float 兼容?
How to check that fortran real is compatible with C float?
我正在使用 iso-c 绑定和 modules/interfaces 等桥接 Fortran 和 C 之间的一些遗留代码。
通常,当将一个 fortran 数组传递给 C 时,我只是将它复制到另一个正确的 iso-c 绑定类型的数组中。然而,一些代码要求我传递一个大的(多 GB)数组。在这种情况下复制它是不明智的。此外,由于它来自第 3 方代码,因此也不可能更改 fortran 数组的类型 real(c_float)
。
不过,如果底层的 Fortran 数组与基于 C 浮点数的 API 不兼容,我很乐意抛出异常或编译失败。
有没有办法在编译时(或运行时)检查默认 real
是否与 C float
或 double
兼容?
如果需要的话,我正在使用 intel fortran 和 C 编译器。
默认 REAL 的种类和与 C 中的 float
互操作的 REAL 的种类之间的比较只是一个简单的整数比较。
您可以使此比较触发编译错误或运行时错误。
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(MERGE(KIND(1.0), -99, C_FLOAT == KIND(1.0)) :: dummy
或
IF (C_FLOAT /= KIND(1.0)) &
ERROR STOP 'Default REAL isn''t interoperable with FLOAT!!'
C_FLOAT 如果 Fortran 处理器没有与之互操作的 REAL 类型,则其本身可能具有负值。
(对于某些 15.0.x 版本的 ifort,以下可用于编译时检查变体:
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
INTEGER, PARAMETER :: dummy_rk = MERGE(C_FLOAT, -99, KIND(1.0) == C_FLOAT)
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(dummy_rk) :: dummy
有几个问题。
C 的 float
作为 C 函数参数和表达式求值的 double
传递。这很容易通过将指针传递给包含定义为 float
(实际上使用 32 位浮点数)的结构或数组来克服。
Intel 的 Fortran 有几种真正的风格:real*4
、real*8
和 real*16
。默认情况下(编译器设置可能会更改这些),real
是真实的*4,double precision
是 real*8
。参见 documentation.
C 的 long double
类型在 Intel Fortran 中没有对应的类型,如果它被实现,将是 real*10
- 它 是 用于 x86 上表达式的中间值。
当然还有 C 与 Fortran 的主要列与次要列数组布局问题(对于多维数组)。
如果是我,我会通过创建一个测试将已知数据(1.0、2.0、3.0、4.0,...)从 C 传递到 Fortran,反之亦然,然后打印值,从而为开发开辟道路或者将它们与它们应该是的进行比较。如果使用非整数,请务必使用适当的 epsilon 比较:
if (abs (c_val - fortran_val) > 0.00001) error();
我正在使用 iso-c 绑定和 modules/interfaces 等桥接 Fortran 和 C 之间的一些遗留代码。
通常,当将一个 fortran 数组传递给 C 时,我只是将它复制到另一个正确的 iso-c 绑定类型的数组中。然而,一些代码要求我传递一个大的(多 GB)数组。在这种情况下复制它是不明智的。此外,由于它来自第 3 方代码,因此也不可能更改 fortran 数组的类型 real(c_float)
。
不过,如果底层的 Fortran 数组与基于 C 浮点数的 API 不兼容,我很乐意抛出异常或编译失败。
有没有办法在编译时(或运行时)检查默认 real
是否与 C float
或 double
兼容?
如果需要的话,我正在使用 intel fortran 和 C 编译器。
默认 REAL 的种类和与 C 中的 float
互操作的 REAL 的种类之间的比较只是一个简单的整数比较。
您可以使此比较触发编译错误或运行时错误。
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(MERGE(KIND(1.0), -99, C_FLOAT == KIND(1.0)) :: dummy
或
IF (C_FLOAT /= KIND(1.0)) &
ERROR STOP 'Default REAL isn''t interoperable with FLOAT!!'
C_FLOAT 如果 Fortran 处理器没有与之互操作的 REAL 类型,则其本身可能具有负值。
(对于某些 15.0.x 版本的 ifort,以下可用于编译时检查变体:
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
INTEGER, PARAMETER :: dummy_rk = MERGE(C_FLOAT, -99, KIND(1.0) == C_FLOAT)
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(dummy_rk) :: dummy
有几个问题。
C 的
float
作为 C 函数参数和表达式求值的double
传递。这很容易通过将指针传递给包含定义为float
(实际上使用 32 位浮点数)的结构或数组来克服。Intel 的 Fortran 有几种真正的风格:
real*4
、real*8
和real*16
。默认情况下(编译器设置可能会更改这些),real
是真实的*4,double precision
是real*8
。参见 documentation.C 的
long double
类型在 Intel Fortran 中没有对应的类型,如果它被实现,将是real*10
- 它 是 用于 x86 上表达式的中间值。当然还有 C 与 Fortran 的主要列与次要列数组布局问题(对于多维数组)。
如果是我,我会通过创建一个测试将已知数据(1.0、2.0、3.0、4.0,...)从 C 传递到 Fortran,反之亦然,然后打印值,从而为开发开辟道路或者将它们与它们应该是的进行比较。如果使用非整数,请务必使用适当的 epsilon 比较:
if (abs (c_val - fortran_val) > 0.00001) error();