- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Try adding "-warn interface" and you might see a clue. You didn't declare dtblu3 as double precision in the caller.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page