我们在一些英特尔FORTRAN代码中遇到了一些奇怪的崩溃,我最终将这条线跟踪到:
L_F = EXP(-L_B2*L_BETASQ*L_DS)
-L_B2 * L_BETASQ * L_DS术语的评估值约为-230。碰巧,EXP(-230)的评估值约为1e-100。在所有其他已知情况下,L_DS要小得多,导致EXP的最小(已知)返回约为1e-50,这不会导致错误。
一旦FORTRAN评估条款EXP(-230),您就得到:
forrtl: severe (157): Program Exception - access violation
Image PC Routine Line Source
但没有其他信息。
异常157通常与互操作性有关,并且您无法在FORTRAN中调试EXP,因为它无法找到特定的.c文件 - 这可能意味着EXP在C中实现(我觉得这很令人惊讶)。
我的假设是FORTRAN在C中实现了EXP,但是接口不能将小于1e-100的浮点数转换为REAL(4)s。正如我之前认为浮点数和REAL(4)s在字节方面相同,我无法支持这个假设 - 而且我找不到任何关于它的任何内容。
在我关闭此错误之前,任何人都可以确认或否认我的假设 - 或者向我提供另一个假设吗?
致以最诚挚的问候,
麦克
编辑:我要将此问题标记为已回答,因为高性能标记已回答了当前的问题。
遗憾的是,我的假设是错误的 - 我试图将问题记录下来:
L_ARG = L_B2*L_BETASQ*L_DS
IF (L_ARG .GT. 230.0) THEN
L_F = 0.0
ELSE
L_F = EXP(-L_ARG)
ENDIF
不幸的是,现在(显然)例外发生在L_ARG .GT中。 230.0条款。这或者意味着发布模式下的调试比我想象的要糟糕,或者它是某种“存储的”浮点错误(参见"Floating-point invalid operation" when inputting float to a stringstream)。
答案 0 :(得分:5)
Fortran没有(必然)在C中实现任何内容。标准内在函数的实现是特定于编译器的;通常会发现实现调用libm
或其中一个亲戚。从英特尔(或任何其他编译器编写者)的观点来看,这是有道理的,用任何语言编写一个强大而快速的exp
实现,并从Fortran,C,Ada,COBOL和其他所有语言中调用它。你听过的语言。用C写出来甚至可能是明智的。因此,你的假设的一部分可能是正确的。
但是,除非你明确地编写C代码和Fortran代码并从中创建一个单独的二进制代码,否则实际上并没有任何互操作性(在Fortran标准意义上),所有的脏细节都被(或应该)隐藏来自你;编译器应该生成对它用于实现exp
的任何库的正确调用,并获得包括NaN
和类似内容的返回值。
当然,对于一个4字节的实数,exp(-230)
的值是0.00000000
但是我没有理由认为使用C编写的库的Fortran程序会引发访问冲突,因为它遇到了那些数字。我认为你的程序中其他地方出现错误的可能性要大得多,可能是试图访问数组范围之外的数组元素,并且运行时无法在源代码中的正确位置识别它。这并不罕见。
修改强>
我在阅读(重新)阅读问题之前写了关于互操作性的内容。既然您已经澄清了您正在使用互操作性功能,那么它可能会引起兴趣或使用......
你绝对不能依赖于你的Fortran real(4)
和你的C float
相同;很可能但不确定。大多数现代Fortran编译器(包括Intel)都使用与其表示中的字节数匹配的类型参数,因此代码4
表示您正在处理一个4字节的实数,在IEEE-754上兼容处理器,应与C float
相同。 Fortran标准不要求那些类型参数与用于表示数字的字节数之间有任何对应关系。总是值得检查您的编译器文档或进行一些测试。
如果您担心互操作性,您可能应该使用Fortran的内在功能。例如,如果你
use :: iso_c_binding
你有许多常量,包括C_FLOAT
,可以像这样使用:
real(C_FLOAT) :: a_fortran_float
如果您的Fortran编译器支持此功能,则a_fortran_float
应与配套处理器上的C float匹配。这个最后一个术语有点不明确,实际上来自同一个稳定的编译器似乎总是同伴,对于不同的稳定,有时是有时没有。英特尔Fortran和C和C ++编译器似乎是所需意义上的伴侣。得知英特尔Fortran和MS C ++编译器不能很好地协同工作并不会让我感到惊讶。
我对C的模糊回忆包含float
标准化的不确定性,在这种情况下,如果不测试或阅读文档,您无法确定您是否确实拥有4字节IEEE单精度互操作那一侧的浮点数。