Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Strange compiler bug?

netphilou31
New Contributor II
2,973 Views

Dear all,

I found a strange compiler bug(?) with the following code:

subroutine ASTMD86_Corrected_to_ASTMD86(ASTMD86Corrected, N, ASTMD86)
!dec$ attributes stdcall, alias:'ASTMD86_Corrected_to_ASTMD86', dllexport :: ASTMD86_Corrected_to_ASTMD86
!dec$ attributes reference :: ASTMD86Corrected, N, ASTMD86
    implicit none

    integer(4), intent(in)  :: N
    real(8),    intent(in)  :: ASTMD86Corrected(N)
    real(8),    intent(out) :: ASTMD86(N)

    integer(4) i, IT

    integer(4) :: ITMAX = 50

    real(8) X, T, F, DFDX

    real(8) :: EPS = 1.D-5
    real(8) :: A = -1.587D0*log(10.D0)
    real(8) :: B = 0.00473D0*log(10.D0)

    ASTMD86(:) = ASTMD86Corrected(:)

    do i=1,N
       T = (ASTMD86Corrected(i)-273.15D0)*9.D0/5.D0 + 32.D0
       if (T > 475.D0) then
           X  = T
           F  = X - T + exp(A+B*X)
           IT = 1
           do while (abs(F) > EPS .and. IT <= ITMAX)
               DFDX = 1.D0 + B*exp(A+B*X)
               X  = X - F/DFDX
               F  = X - T + exp(A+B*X)
               IT = IT + 1
           end do
           ASTMD86(i) = (X-32.D0)*5.D0/9.D0 + 273.15D0
       end if
    end do

end subroutine ASTMD86_Corrected_to_ASTMD86

It appears that the variable A is assigned to -0.0000000D+00, whereas the variable B is correctly evaluated.

I seems that the problem is at least present from the first version of OneAPI. I don't know if it was present in previous versions (XE2019 or XE2020), but it worked in versions prior to OneAPI.

My compiler switches are:

/nologo /O2 /fpp /extend-source:132 /Qsave /assume:byterecl /Qzero /fpe:1 /fp:source /fpconstant /Qfp-speculation=strict /iface:cvf /module:"Win32\Release\\" /object:"Win32\Release\\" /Fd"Win32\Release\vc160.pdb" /libs:static /threads /Qmkl:sequential /c

Fortunately, solving the issue was quite easy, I simply replaced the declaration / initialization statements by manual initialization of the variables A and B before the loop, but that's really weird! I will have to check if no other code is impacted with this problem.

Best regards,

0 Kudos
1 Solution
Ron_Green
Moderator
2,757 Views

Our engineer is triaging this one.  It's certainly curious.  Interestingly, she found this work around:

 

real(dp) :: a = (-1.587d0) *log(10.d0)

It affects negative constants, which was pretty obvious from 'b's initialization 

View solution in original post

0 Kudos
28 Replies
JohnNichols
Valued Contributor III
868 Views
real(dp) :: a = (-1.587d0) *log(10.d0)
Does () change the order of operations?
In the original, I would assume log() followed by multiplication and then negation, whilst the engineer, who at this stage is nameless, it would be nice to know the name of the said engineer unless it is a state secret.  As in Harry Potter, she, who will not be named turned it into negation, log operation and then multiplication. 
Interesting.  
 
Does the compiler complain about the extra ()? 
 
0 Kudos
FortranFan
Honored Contributor II
817 Views

@netphilou31 ,

 

Re: "I know that initializing variables this way turn them as SAVED. However, they are not supposed to change at run time, so I guess that's not a problem even for thread safety (am I wrong?),"

- you will be surprised at the "race condition" issue with static data in code that can arise with the simplest of instances, caveat emptor!

0 Kudos
Steve_Lionel
Honored Contributor III
839 Views

@JohnNichols , you may want to read my post on that topic: Doctor Fortran in "Order! Order!" - Doctor Fortran (stevelionel.com)

In the case you give, and if the parentheses are absent, the negation is done after the multiply (though arithmetically the result would be the same if the negation were done first.) The "extra parentheses" are perfectly fine and appropriate - note, however, that ifort may ignore them unless you use /assume:protect_parens.

0 Kudos
JohnNichols
Valued Contributor III
810 Views

Thank you, yes, I really prefer the () in Lisp that forces the programmer to decide the order of operation and then there is no ambiguity. 

I thought it was rather brilliant of the unnamed programmer from Intel to try that solution, whomever they are, they are very bright or perceptive.  And of course, nameless.  

I prefer to take the constant and place it in a module that can be reused as required in other code, as @mecej4 showed me on the Magni code.  I wish I had time to play with that code, water supply is so much fun.  

In this case, IFORT has not ignored them, as it has fixed the problem.  

 

Edited for commas. 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
773 Views

>>Fortunately, solving the issue was quite easy, I simply replaced the declaration / initialization statements by manual initialization of the variables A and B before the loop, but that's really weird! 

I (strongly) suggest you investigate this further by restoring the initialization at compile time, then instead of initializing as part of the procedure that you insert an assert to assure that the values have not changed (from that of the compiler initialization).

The reason you should do this, is if those values are being changed, that this is an indication of a (serious) bug elsewhere in your code. Note, if you do discover a change in values, then you can use the debugger to break on data change (at the locations of A/B)

Jim Dempsey

0 Kudos
netphilou31
New Contributor II
749 Views

Hi Jim,

Thanks for the advice, however in this case the procedure (located in a tools dll) is called from another dll just to perform a conversion from a given distillation curve (atmospheric TBP) to an ASTM D86 curve, so I will be surprised that a serious bug would affect these variables but who knows?

Best regards,

0 Kudos
Ron_Green
Moderator
723 Views

@netphilou31  I would suggest using compiler option /debug-parameters:all or -debug-parameters all

this will preserve PARAMETER symbols that can be viewed in the debugger.  with vanilla /debug, as you know, PARAMETER symbols are not preserved in the debug symbol table.  Adding this option keeps the symbolic name for them.

Another handy tool for your toolbox of debug tricks.

0 Kudos
netphilou31
New Contributor II
716 Views

Hi Ron,

Thanks for the trick, this is something I am using for long. It's indeed particularly useful when debugging an application to be able to look at the PARAMETER symbols values.

Best regards,

0 Kudos
Reply