【问题标题】:How to check that fortran real is compatible with C float?如何检查 fortran real 是否与 C float 兼容?
【发布时间】:2016-03-23 03:55:12
【问题描述】:

我正在使用 iso-c 绑定和模块/接口等在 fortran 和 C 之间桥接一些遗留代码。

通常,当将一个 fortran 数组传递给 C 时,我只需将其复制到另一个具有正确 iso-c 绑定类型的数组中。然而,一些代码需要我传递一个大(多 GB)数组。在这种情况下,复制它是不明智的。此外,由于它来自第 3 方代码,因此也无法更改无用 real(c_float) 的 fortran 数组的类型。

但是,如果底层的 fortran 数组与基于 C 浮点的 API 不兼容,我很乐意抛出异常或编译失败。

有没有办法在编译时(或运行时)检查默认 real 是否与 C floatdouble 兼容?

如果重要的话,我正在使用 intel fortran 和 C 编译器。

【问题讨论】:

  • 为什么说复制多 GB 数组是明智的?目标是什么类型的硬件?
  • @wallyk 主要是因为我已经接近机器上的内存限制。在已用内存中再添加 4GB 会导致应用程序崩溃——或将我推入交换状态——其中任何一种都是不可接受的。
  • 我建议查看 Fortran 编译器手册。然而,在过去(又名 Fortran 77),REAL 也是 REAL*4,而不是双精度的 REAL*8 — 那是双精度吗? — 因此,Fortran REAL 与 C 浮点数相同的可能性非常高。如果由于某种意外或设计,Fortran REAL 是 Cdouble,那么您将能够使用未复制的数组,不是吗? AFAICR,如果你在 C 代码中修改数组,它也会在调用函数中被改变——就像 C 一样。
  • 你可以试试写real (OriginalArray, c_float)。如果OriginalArrayc_float 属于同一类型,则可能希望将内在real 写入数组之后。如果它是不同的类型,那么它会生成c_float 类型的临时副本。也许会有足够的内存......
  • @JonathanLeffler 在过去的日子里,使用这些简单假设不正确的奇怪机器的几率比今天(各种 24 位或 48 位机器和其他机器)大得多。

标签: c fortran fortran-iso-c-binding


【解决方案1】:

默认 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!!'

如果 Fortran 处理器没有与之互操作的 REAL,C_FLOAT 本身可能有一个负值。

(对于某些 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

【讨论】:

  • 编译时检查我得到error #6683: A kind type parameter must be a compile-time constant. [MERGE]
  • @MichaelAnderson 为dummy 变量提供种类的表达式需要 F2003 支持。我怀疑您没有使用最近的 ifort 版本。它适用于 16.0.2。
  • 是的,现在坚持使用 15。所以我猜我现在只能使用运行时版本,
  • 好的 - 如果您使用一些中间命名常量简化编译器的表达式,那么对于 15.0 的某些版本,它将起作用。见编辑。
  • 我没有看到 real*4、默认 real、C_FLOAT 的种类需要相同,即使浮点表示相同。我不明白这里想要什么。如果您是偏执狂,您可能会运行老式测试来查看与数据类型关联的 EPSILON 值是否可以匹配。
【解决方案2】:

有几个问题。

  • C 的 float 作为 double 传递给 C 函数参数和表达式求值。这可以通过将指针传递给包含定义为float 的变量的结构或数组来轻松克服(实际上使用的是 32 位浮点数)。

  • 英特尔的 Fortran 有几种真实风格:real*4real*8real*16。默认情况下(编译器设置可能会改变这些),real 是真实的*4,double precisionreal*8。请参阅documentation

  • C 的 long double 类型在 Intel Fortran 中没有等价物,其中——如果它被实现,将是 real*10——它确实用于 x86 上表达式的中间值.

  • 当然存在 C 与 Fortran 的主要列与次要列数组布局问题(对于多维数组)。

如果是我,我会为开发开辟道路他们应该是什么。如果使用非整数,请务必使用适当的 epsilon 比较:

           if (abs (c_val - fortran_val) > 0.00001)  error();

【讨论】:

    猜你喜欢
    • 2011-02-10
    • 1970-01-01
    • 2015-04-04
    • 2015-10-14
    • 2017-01-05
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多