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

call to fortran double precision function returning garbage

Dane_A_
Beginner
652 Views

Environment: Suse linux,

I have a real function tbl that is invoking a fortran function. The function is double precision, the variable catching the return is also double. I have inserted write statements just before the return, and just after the value is caught. The two do NOT match.

dtblu3 is in a utility library that MANY other applications use. tbl is part of an analysis application that mixes C, Fortran, and Oracle's Pro C code.

      real function tbl (a,v,d,ier)

      real a(*),v(*),d(*)
      double precision xi,yi,zi, f3(10000)
      double precision dval, dd, da, xary(100), yary(100), zary(100)

      double precision my_tbl

...

            my_tbl = dtblu3(xi,yi,zi,xary,yary,zary,f3,ndx,ndy,ndz,nx,
     1                  ny,nz,nxa,nya,nza)
      write(*,*) "tbl point 1 my_tbl = ", my_tbl

 

      double precision function dtblu3( x1, y1, z1, x, y, z, f3,
     +                                  ndx, ndy, ndz, nx, ny,
     +                                  nz, mx, my, mz )

      double precision  x(*), y(*), z(*), f3(mx,my,mz)                             
      double precision  x1, y1, z1, x2, y2, z2, dterp3

...

            dtblu3 = f3(i,j,k)                                                 
      write(*,*) 'dtblu3 point 1 dtblu3 = ', dtblu3
            return

The output from these write statements is

 dtblu3 point 1 dtblu3 =    1.34000003337860
 tbl point 1 my_tbl =  -3.689348814741910E+019


The compile statement for dtblu3.f is:

/ots/sw/Intel/compilers_and_libraries_2016.1.150/linux/bin/intel64/ifort -c  -I../include dtblu3.f


The compile statement for tbl.f is:

/ots/sw/Intel/compilers_and_libraries_2016.1.150/linux/bin/intel64/ifort -g -C -c -assume byterecl -convert big_endian -check -I /boeing/include -I/usr/include -I/net/psn02hom/home/d/dra3556/work/vobs/libutil/dvlp/include tbl.f

 

So, any ideas on where my problem might be originating?

 

 

 

0 Kudos
9 Replies
Steven_L_Intel1
Employee
652 Views

Try adding "-warn interface" and you might see a clue. You didn't declare dtblu3 as double precision in the caller.

0 Kudos
mecej4
Honored Contributor III
652 Views

Another way of elucidating the mystery is to examine the internal representation of 4-byte and 8-byte IEEE reals.

The 8-byte representation of your 1.34... is Z'3FF5 70A3 DFFF FFFB ' (I have added separators after 4 nybbles for readability). Because of the error in your program, only the low-order four bytes of this number are stored, namely, Z'DFFF FFFB'. This number, decoded as a 4-byte real, is your other number, -3.689...E+19.

The old CVF compiler package included a useful utility, BitView, for help with these conversions.

0 Kudos
TimP
Honored Contributor III
652 Views

Also, CVF (and other compilers for 387 mode) returned both single and double precision function results in the same register (no conversion needed), so hiding latent bugs such as this.

0 Kudos
Dane_A_
Beginner
652 Views

THANK YOU. Adding:

double precision dtblu3

 

to the calling function did indeed fix the problem. I am in the process of porting the application from AIX to

linux. On AIX this declaration is not needed. Don't ask me why.

 

The add -warn interface did NOT work. Added to the compile line did nothing. Added to the link line errored out.

0 Kudos
mecej4
Honored Contributor III
652 Views

Dane A. wrote:

Adding "double precision dtblu3" to the calling function did indeed fix the problem. On AIX this declaration is not needed. Don't ask me why.

You should ask why, and fix the error in the program on AIX, too. Here is an example that should alert you to the risks of such errors remaining hidden, as Tim P. warned.

program tst
x=1.2
write(*,*)x,sqr(x)
end

double precision function sqr(x)
sqr=x*x
return
end

Compiled with the default option (which includes optimization), in the program the result sqr(x) is evaluated at compile time, so you do not see the error. Recompiling in 64 bits with /Od and running gives the output

        1.200000      0.0000000E+00

In 32 bit mode, with or without /Od, the output is

        1.200000       1.440000

With /Od, the result of the function is passed as a 80-bit value in register ST0, so the error remains hidden.

The add -warn interface did NOT work. Added to the compile line did nothing. Added to the link line errored out.

With the above test program, I get the following message with /warn:interfaces:

ferr.f90(3): error #7977: The type of the function reference does not match the type of the function definition.   [SQR]

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
652 Views

It would be best to produce your own interfaces module rather than use the auto-generated interfaces. Not all compilers will support auto-generated interface modules.

Also note, that for your interfaces module, you cannot use the interfaces module inside the subroutine/function interfaced. For some reason the Fortran standards committee rejected this. IMHO by permitting this, it would provide an ASSERT to assure any change in one file would be assured in the other file. (older versions of the compiler permitted this, newer ones did not, I haven't tried again with the latest V17)

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
652 Views

Rather than an "interfaces module", put procedures in a "regular" module or make them contained procedures. In general if you are writing new code and have interface blocks for Fortran procedures (and aren't using submodules), you're doing it wrong.

17.0 doesn't allow the nonstandard interface-to-self and we have no plans to change that until the standard does.

0 Kudos
jimdempseyatthecove
Honored Contributor III
652 Views

It is not often possible, or should I say practical, to restructure code into a hierarchy of modules, where the only file that is not a module is the PROGRAM procedure. I suppose it won't become apparent to the committee that there is a valuable benefit to having interface-to-self (for the express purpose of interface verification) until they personally run into situation(s) where it would be handy.

Recently I had one such situation in a moderately sized project where I had to add one, then two context arguments to various subroutines and functions. Not having this ability resulted in several hours, possibly a few days of debugging due to not having a convenient way for self verification of interfaces (errors would only show up during runtime, screwy results, or if lucky, program crash). If the user community (like myself) do not prod committee members for this feature, it will never be fully considered.

Let me propose an alternative to interface-to-self (or more appropriately stated verification of interface of self):

Have the linker assert the correctness of the interface by producing function(subroutine) signatures as is done with C++. I imagine that this would be more difficult for the committee to swallow than interface-to-self.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
652 Views

I did say "new code". I understand that if you're modifying a large, existing code that such restructuring is harder.

The Fortran standard doesn't know the term "linker", and takes the approach that it describes a standard-conforming program. The standard already requires that the "characteristics" of a procedure be consistent with its caller (with certain exceptions) but leaves it up to the programmer to verify that (except in the case of explicit interfaces). The sort of checking you describe is exactly what we do with -warn interface, though it isn't a perfect solution (since it depends on build order), but it's a lot better than nothing.

Fortran would never go in for C++-style name mangling.

0 Kudos
Reply