Hi,
I am trying to understand if my interpretation of nested WHERE blocks is incorrect or if the compiler is producing an incorrect execution.
I encountered numerical floating point exceptions in a large program because of the execution of LOG10(0.D00) inside a nested WHERE block, even though execution of array arguments with values <= 0.0D0 should be prevented by a mask in the outer WHERE block.
The following test code reproduces the problem when the compiler flag /fpe:0 is set for floating point exception handling.
!** A simple program to test issues with nested WHERE constructs ** PROGRAM NestedWHERE IMPLICIT NONE INTEGER(4) :: j INTEGER(4), PARAMETER :: n = 4, k = 100 REAL(8),DIMENSION(n) :: arrayA, arrayB, arrayC, arrayD !------------------------------------------------------- arrayA = [1.0D0, 2.0D0, 0.0D0, 4.0D4] arrayB = [1.0D0, 2.0D-2, 0.0D0, 4.0D-6] !Nested WHERE block WHERE (arrayA(1:n) > 0.0D0) WHERE (ABS(LOG10(arrayA(1:n))) + ABS(LOG10(arrayB(1:n))) < 300.0D0) !issue: LOG10 seems to be executed for all array elements (including elements where arrayA == 0.0D0). Why is the mask (of the outer WHERE) not applied? arrayC(1:n) = arrayB(1:n)/arrayA(1:n) ELSEWHERE arrayC(1:n) = 8.0D-4 ENDWHERE ELSEWHERE arrayC(1:n) = 1.111111111 ENDWHERE !The procedure of the above nested WHERE block expressed by DO-loop and nested IF-END IF blocks (works as expected). DO j = 1,n IF (arrayA(j) > 0.0D0) THEN IF (ABS(LOG10(arrayA(j))) + ABS(LOG10(arrayB(j))) < 300.0D0) THEN arrayD(j) = arrayB(j)/arrayA(j) ELSE arrayD(j) = 8.0D-4 ENDIF ELSE arrayD(j) = 1.111111111 ENDIF ENDDO !J WRITE(*,'(A23)') " arrayC, arrayD " DO j = 1,n WRITE(*,'(2(ES12.4,2x))') arrayC(j), arrayD(j) ENDDO WRITE(*,*) "" WRITE(*,*) "... done." READ(*,*) END PROGRAM
I use the Intel(R) Visual Fortran Compiler 16.0.0.110 [IA-32], in MS Visual Studio 2010 on Windows 7.
The ifort command line used is:
/nologo /debug:full /Od /warn:interfaces /fpe:0 /fp:source /module:"Debug\\" /object:"Debug\\" /Fd"Debug\vc100.pdb" /traceback /check:bounds /check:stack /libs:static /threads /dbglibs /c
The following is an excerpt of the call stack at the point of floating point exception:
TestNestedWHERE.exe!___libm_log10_w7() + 0x226 bytes
TestNestedWHERE.exe!NESTEDWHERE() Line 15 + 0x45 bytes Fortran
I am not sure if my use of nested WHERE statements in this case is incorrect (even though both ABS and LOG10 are elemental intrinsic functions) or if it is supposed to work according to the Fortran standard.
Andi