我希望我有一个最低限度的工作示例!
我正在使用HSL libraries做一堆线性代数。我打开了我能想到的每一个调试标志。
在我的工作站上,我的“确定性”代码的最终结果很少有效。大多数时候,它抱怨索引错误:
forrtl: severe (408): fort: (3): Subscript #1 of the array W has value 0 which is less than the lower bound of 1
Image PC Routine Line Source
libintlc.dylib 0000000103C83E04 Unknown Unknown Unknown
libintlc.dylib 0000000103C8259E Unknown Unknown Unknown
libifcore.dylib 00000001031FBDA1 Unknown Unknown Unknown
libifcore.dylib 000000010316BA4E Unknown Unknown Unknown
libifcore.dylib 000000010316BFB3 Unknown Unknown Unknown
forrtl: severe (408): fort: (3): Subscript #1 of the array A has value 0 which is less than the lower bound of 1
Image PC Routine Line Source
libifcore.dylib 000000010ABDCC96 Unknown Unknown Unknown
Uniform2DSimplifi 00000001068851EE _ma48bd_ 1461 ma48d.f
Uniform2DSimplifi 000000010693619C _solve_sparse_mat 142 solve_sparse_matrix_d.f90
Uniform2DSimplifi 000000010693A7D8 _scale_and_solve_ 128 scale_and_solve_sparse_matrix_d.f90
Uniform2DSimplifi 000000010685740D _calc_simplified_ 598 calc_simplified_equations_B.f90
Uniform2DSimplifi 0000000106832176 _MAIN__ 161 uniform_2D_simplified_B.f90
Uniform2DSimplifi 000000010683175E Unknown Unknown Unknown
(您可能会注意到这些实际上是两个不同的错误,即使我没有更改它们之间的代码行。)
我的代码在我的笔记本电脑上使用较新版本的ifort
成功运行~70%的时间,但只有约20%的时间在我的工作站上使用旧版ifort
。奇怪的是,它运行的时间通常是在新的编译之后,并且在工作一次之后,它每次都会在此之后给出错误。有一次它工作,第二次没有工作,然后第三次工作。 (有时在我的笔记本电脑上,它适用于前2-3次运行,但第四次抛出错误。)
我自己的代码完全是确定性的:它正在设置解决线性代数例程。它还调用HSL例程,显然称为MKL。我认为HSL和MKL都是确定性的 - 也就是说,相同的输入产生相同的输出。 (他们不会调用RAND()或文件I / O ....)不过,我不确定。
我抬头看了ma48d.f的第1461行:
CALL MA50BD(NR,NC,NZB,JOB5,A(K+1),IRN(K+1),KEEP(IPTRD+J1),
+ CNTL5,ICNTL5,IW(J1),IQB,NP,LA-NEWNE-KK,
+ A(NEWNE+KK+1),IRN(NEWNE+KK+1),KEEP(IPTRL+J1),
+ KEEP(IPTRU+J1),W,IW(M+1),INFO5,RINFO5)
在我的笔记本电脑上,它抱怨,因为k
的值-1
(导致错误),而它通常具有值0
(导致成功)。有趣的是,我给这些例程提供了完全相同的输入,并且代码似乎是确定性的,因此它们应该执行完全相同的行...但它们不会。
可能导致这种不稳定行为的原因是什么?
到目前为止,我已经考虑过以下几种可能性:
答案 0 :(得分:3)
根据我的经验,编译器比程序员更可靠。也就是说,除非可以证明生成了错误的代码,否则我会怀疑编程错误的程序。
这种错误肯定是由于使用了未初始化的值。在使用之前,查找未特别设置为某个值的变量。
program x
integer :: i, arr(10)
do while (i < 10)
arr (i) = 0
i = i + 1
enddo
print *, arr
end
有时,此代码会将所有元素设置为零。其他时候它不会改变一件事。
在此逻辑中发生了直接相关但更微妙的缺少初始化错误:
program y
integer :: sum, i, arrA(10), arrB(10)
real :: ave(2)
do i = 1, 10
arrA(i) = i * 343
arrB(i) = i * 121
enddo
sum = 0
do i = 1, 10
sum = sum + arrA(i)
enddo
ave(0) = sum / 10.0
do i = 1, 10
sum = sum + arrB(i)
enddo
ave(1) = sum / 10.0
print *, 'Averages are', ave
end
如果无法重新初始化sum
,则不会显示编译器警告,尽管此类错误具有可重现性和确定性。
答案 1 :(得分:1)
我无法添加评论 - 因此答案。
您还可以尝试-ftrapuv(将堆栈变量初始化为异常值)。如果您使用的是英特尔15或更高版本,则可以设置-init = snan。这会初始化“保存”变量以指示NaN。