Vla*_*nko 3 fortran if-statement
我有一个子例程ran_init ( length ),其中一条IF语句工作不正确。
下面的代码是我的原始代码的高度简化版本:
\nMODULE 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\nRun Code Online (Sandbox Code Playgroud)\n此代码返回结果:
\n 2147483647 -2147483648 -2147483648 0\n nrerror: ran_init: arith assump 3 fails\nSTOP program terminated by nrerror\nRun Code Online (Sandbox Code Playgroud)\n可以看出,值hgt + 1和hgng彼此相等,但在IF语句中这些值被解释为不相等。
为什么会发生这种情况?
\nUPD \xe2\x84\x961\n一些技术细节:
\ngfortran编译器gfortran --version返回GNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609\nRun Code Online (Sandbox Code Playgroud)\n-O2 -Wall -Wextra -fbacktrace -fcheck=all -g -o\nRun Code Online (Sandbox Code Playgroud)\n具有一定程度的优化不会影响结果。
\nUPD \xe2\x84\x962
\n我不知道为什么,但如果创建一个新变量,例如hgtp类型INTEGER ( K4B )和替换行
hgt = hg\nPRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng\nIF ( hgt + 1 .NE. hgng ) CALL nrerror ( \'ran_init: arith assump 3 fails\' )\nRun Code Online (Sandbox Code Playgroud)\n有线条
\nhgt = hg\nhgtp = hgt + 1\nPRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng\nIF ( hgtp .NE. hgng ) CALL nrerror ( \'ran_init: arith assump 3 fails\' )\nRun Code Online (Sandbox Code Playgroud)\nIF 语句开始将条件解释hgtp .NE. hgng为 true。
您遇到了整数溢出,这是 Fortran 中未定义的操作。这意味着 Fortran 处理器(编译器和运行时)可以做任何它喜欢的事情,比如做一些或多或少的随机计算,用错误消息中止编译,在运行时用错误消息中止程序,或者启动火箭发动第三次世界大战。
这意味着如果发生整数溢出,您不能依赖某些特定行为。一般来说,假设没有发生溢出,编译器会尽可能快地优化代码(因为这是未定义的行为,程序员有责任确保程序不会进入这种状态)。
此外,这里有两种溢出:
hgt + 1有点明显,因为hgt等于HUGE()。hgm - 1也是溢出。这不是使用整数的补码表示的硬件上的溢出(实际上,现在所有的硬件都可能是博物馆藏品之外的),但是 Fortran 型号是对称的,所以在 Fortran 标准中这是一个溢出,并且再次,所有的赌注都落空了。(上面假设您正在运行的系统上,默认整数与K4B当今大多数系统具有相同的类型,除非您使用某些-fdefault-integer-8或此类选项)