IF 语句的工作方式相反

Vla*_*nko 3 fortran if-statement

我有一个子例程ran_init ( length ),其中一条IF语句工作不正确。

\n

下面的代码是我的原始代码的高度简化版本:

\n
MODULE ran_state\nUSE nrtype\nIMPLICIT NONE\n\nINTEGER, PARAMETER :: K4B = SELECTED_INT_KIND ( 9 )\nINTEGER ( K4B ), PARAMETER :: hg = HUGE ( 1_K4B ), hgm = -hg, hgng = hgm - 1\nINTEGER ( K4B ), SAVE :: lenran = 0\n\nCONTAINS\n\nSUBROUTINE ran_init ( length )\nUSE nrtype; USE nrutil, ONLY: nrerror\nIMPLICIT NONE\n\nINTEGER ( K4B ), INTENT ( IN ) :: length\nINTEGER ( K4B ) :: hgt\n\nIF ( length < lenran ) RETURN\nhgt = hg\nPRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng\nIF ( hgt + 1 .NE. hgng ) CALL nrerror ( \'ran_init: arith assump 3 fails\' )\n\nEND SUBROUTINE\n\nEND MODULE ran_state\n
Run Code Online (Sandbox Code Playgroud)\n

此代码返回结果:

\n
  2147483647 -2147483648 -2147483648           0\n nrerror: ran_init: arith assump 3 fails\nSTOP program terminated by nrerror\n
Run Code Online (Sandbox Code Playgroud)\n

可以看出,值hgt + 1hgng彼此相等,但在IF语句中这些值被解释为不相等。

\n

为什么会发生这种情况?

\n

UPD \xe2\x84\x961\n一些技术细节:

\n
    \n
  1. 我用作gfortran编译器
  2. \n
  3. 命令gfortran --version返回
  4. \n
\n
GNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 我用标志编译我的程序
  2. \n
\n
-O2 -Wall -Wextra -fbacktrace -fcheck=all -g -o\n
Run Code Online (Sandbox Code Playgroud)\n

具有一定程度的优化不会影响结果。

\n
    \n
  1. 我的操作系统是 Ubuntu 16.04LTS 64 位
  2. \n
\n

UPD \xe2\x84\x962

\n

我不知道为什么,但如果创建一个新变量,例如hgtp类型INTEGER ( K4B )和替换行

\n
hgt = hg\nPRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng\nIF ( hgt + 1 .NE. hgng ) CALL nrerror ( \'ran_init: arith assump 3 fails\' )\n
Run Code Online (Sandbox Code Playgroud)\n

有线条

\n
hgt = hg\nhgtp = hgt + 1\nPRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng\nIF ( hgtp .NE. hgng ) CALL nrerror ( \'ran_init: arith assump 3 fails\' )\n
Run Code Online (Sandbox Code Playgroud)\n

IF 语句开始将条件解释hgtp .NE. hgng为 true。

\n

jan*_*neb 6

您遇到了整数溢出,这是 Fortran 中未定义的操作。这意味着 Fortran 处理器(编译器和运行时)可以做任何它喜欢的事情,比如做一些或多或少的随机计算,用错误消息中止编译,在运行时用错误消息中止程序,或者启动火箭发动第三次世界大战。

这意味着如果发生整数溢出,您不能依赖某些特定行为。一般来说,假设没有发生溢出,编译器会尽可能快地优化代码(因为这是未定义的行为,程序员有责任确保程序不会进入这种状态)。

此外,这里有两种溢出:

  • hgt + 1有点明显,因为hgt等于HUGE()
  • hgm - 1也是溢出。这不是使用整数的补码表示的硬件上的溢出(实际上,现在所有的硬件都可能是博物馆藏品之外的),但是 Fortran 型号对称的,所以在 Fortran 标准中这是一个溢出,并且再次,所有的赌注都落空了。

(上面假设您正在运行的系统上,默认整数与K4B当今大多数系统具有相同的类型,除非您使用某些-fdefault-integer-8或此类选项)