Different results for LOG10 in Fortran on Windows and Linux - fortran

I've been working on mixed C++/Fortran numerics code that needs to run on Windows and Linux and traced a discrepancy to the LOG10 function. I'm using gcc/gfortran on Linux and MinGW on Windows.
Here's an example:
PROGRAM FP
REAL VAL1, VAL2, ARG
DATA VAR1 / 12.5663710 /
DATA VAR2 / 10.6640625 /
DATA VAR3 / 1.08791232 /
ARG = VAR1 * VAR2 / VAR3
VAL1 = LOG10 (VAR1 * VAR2 / VAR3)
VAL2 = LOG10 (ARG)
WRITE (*,"(F30.25)") ARG
WRITE (*,"(F30.25)") LOG10(ARG)
WRITE (*,"(F30.25)") VAL1
WRITE (*,"(F30.25)") VAL2
END PROGRAM FP
On Linux, I get:
123.1795578002929687500000000
2.0905385017395019531250000
2.0905385017395019531250000
2.0905385017395019531250000
On Windows, I get
123.1795578002929687500000000
2.0905387401580810546875000
2.0905387401580810546875000
2.0905387401580810546875000
The same values are going into LOG10, but 2.09053850 is coming out on Linux and 2.09053874 on Windows. This is enough of a difference to cause substantial problems with testing. What can I do to get the same answer on both platforms?
I'm using someone else's Fortran code and am not an expert in its floating-point implementation details but found the problem by tracing the code side-by-side until the values diverged. The LOG10 seems to be the culprit.
As for compiler versions, on Linux I get:
$ gfortran --version
GNU Fortran (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
On Windows:
> gfortran --version
GNU Fortran (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0

The difference comes by using a different runtime library. The log10 function implementation does not come from the libgfortran runtime library. Instead, on Linux, the standard C library GNU libc (GLIBC) is called https://www.gnu.org/software/libc/manual/html_node/Exponents-and-Logarithms.html (it is in the libm part).
Other compilers will do differently. Intel Fortran has its own runtime library and it actually gives the answer 2.0905387401580810546875000 on Linux.
On Windows it could depend on the GCC distribution you use. If you are using MinGW, then the Microsoft C runtime library is used instead of the GNU C library.
As far as I know, GLIBC is not available on Windows at all (Can I use glibc under windows?). You might try to take the log function from there and link it with your program but you will have to dig into the internals quite deeply.

A consistent answer across platforms should be attained by promoting the argument of the log10 function to double precision and then converting the result back to single. Try the following function
`
real function mylog10(rarg)
integer, parameter :: dp = selected_real_kind(15,9)
real, intent(in) :: rarg
mylog10=log10(real(rarg,kind=dp))
end function mylog10
`
I get 2.0905387401580810546875000 for both Intel and gfortran on Linux. You could even make the function elemental if working on arrays.

Related

Does C++17 provide a cross-platform scheme to record compiler version and options like Fortran?

Question
Modern Fortran offers a few cross-platform mechanisms to record the compiler version and settings used to build an application. What methods does C++17 have to capture this information? The book by Horton and Van Weert, Beginning C++17, does not appear to address this question.
The Fortran tools are surveyed below.
1. Access to compiler versions and options
The iso_fortran_env in Fortran provides a standard way to access the compiler version and settings used to compile a code. A sample snippet follows.
Code sample
program check_compiler
use, intrinsic :: iso_fortran_env, only : compiler_options, compiler_version
implicit none
write ( *, 100 ) "compiler version = ", compiler_version ()
write ( *, 100 ) "compiler options = ", trim ( compiler_options () )
100 format ( A, A, / )
stop "normal termination . . ."
end program check_compiler
Sample output
$ gfortran -o check_compiler check_compiler.f08
$ ./check_compiler
compiler version = GCC version 8.0.0 20170604 (experimental)
compiler options = -fPIC -mmacosx-version-min=10.12.7 -mtune=core2
STOP normal termination . . .
2. Probing and interacting with host OS
Fortran commands like execute_command_line, get_command, and get_environment_variable offer another route to record information at compile time.
What methods does C++17 have to capture this information?
None. The C++ standard does not even recognize the concept of "compiler" or "options"; there is merely the "implementation".
Furthermore, it would not really make sense, as different C++ files linked into the same program can be compiled with different options. And I'm not just talking about DLL/SOs; you can in theory statically link files that were compiled with different options or even different compiler versions.
Different compilers have ways to specify what version they are through macros. But each one has its own way to report this.
Searching the C++20 standard draft, which is available in GitHub, I find no results for closely-localted "compiler" and "version", nor have I found something like this looking at the text of the standard.
C++20 is at this time still very close to C++17, and certainly such a mechanism has not been removed, so I think it's pretty safe to say that there's no such thing in C++20.
Each compiler injects their own preproxessor tokens indicating itmwas compiled by them, and what version. These tokens are cross platform on compilers that compile on and to kore than one platdorm, such as icc, gcx and clang.
There are now standard defined ways to detect the existence of some srd header files. Boost has extensive headers that decode compiler capabilities based of a myriad of techniques.
__cplusplus in theory is defined to the standard version, but compilers lie.
The language standard specifies macros __cplusplus that encode the version of the standard that the compiler claims to support. It expands to 201703L on a C++17 compiler, 201710L on a C++14 compiler, and so on. It might also define _STDC and _STDC_VERSION. Beyond that, everything is a vendor-specific extension that you should look up in your compiler's manual.
Some but not all compilers, including GCC and Clang, predefine a macro named __VERSION__ that expands to a string describing the compiler version. You can check for this with #ifdef. Beyond that, many compilers contain macros that expand to version numbers, which you can stringify and concatenate. However, be aware that some compilers treat these as compatibility tests, and will claim to be a different compiler if you ask. In addition to its own version numbers, Clang defines __GNUC__, __GNUC_VERSION__ and __GNUC_PATCHLEVEL__ to indicate its compatibility with GCC, and the Windows version will also define _MSC_VER, _MSC_FULL_VER and so on in its Microsoft-compatiblity mode.
You could therefore create a complicated set of nested #elif blocks to recognize various compilers' version macros, but it could never be complete or forward-compatible.

Fortran compiler options not recognized [duplicate]

This question already has an answer here:
Compiling issue with ifort composer_xe_2015.3.187
(1 answer)
Closed 7 years ago.
I am using a numerical model that is sensitive to the precision of numerics. With my old ifort compiler I successfully used the Fortran flags
"fp-model precise"
I recently installed intel compiler composer_xe_2015.3.187. It does not recognize the Fortran flag
"fp-model precise".
This is the exact error that I get
f95: error: precise: No such file or directory
f95: error: unrecognized command line option ‘-fp-model’
I am afraid if I would be sacrificing my efficiency in lieu of the new compiler or is the new one inherently able to maintain precision.
The compiler you are invoking with the name f95 is not Intel Fortran. Based on the error message, I'm guessing it is actually the GNU Fortran compiler, but you can check for sure by running f95 -v to see what the compiler identifies itself as.
Intel Fortran 15 still supports the option -fp-model precise.
Before invoking ifort, you need to setup its environment, e.g.
source /path/to/intel/bin/ifortvars.sh intel64
for the 64 bit compiler. You can then invoke the compiler as ifort.

Horrid error with strtod(): glibc-2.13 NOT backwards compatible with glibc-2.9?

I'm working on C and C++ programs which need to run on several different embedded platforms, for which I have cross-complilers so I can do the build on my x86 desktop.
I have a horrible problem with certain functions, e.g. "strtod()". Here's my simple test program:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if ( (argc < 2) || (NULL == argv[1]) ) return 0;
double myDouble = strtod(argv[1], NULL);
printf("\nValue: %f\n\n", myDouble);
return 0;
}
Normally I build all programs with dynamic linking to keep the binaries as small as possible. The above works fine on the x86 and Power PC. However, on the Arm system (BeagleBoard xM with Debian) strtod() misbehaves (the program always outputs "0.000000").
I tried building the program with the option '-static', and that worked on the Beagle:
root#beaglexm:/app# ./test.dynamic 1.23
Value: 0.000000
[Dynamic linked version - WRONG!!]
root#beaglexm:/app# ./test.static 1.23
Value: 1.230000
[Correct!!]
I also tested on a BeagleBone Black, which has a slightly different distribution. Both versions (static and dynamic) worked fine on the BBB.
Digging around in the libraries, I found the following version numbers:
Cross Compiler Toolchain: libc-2.9.so
BeagleBoard XM (DOESN'T WORK): libc-2.13.so
BeagleBone Black (WORKS!): libc-2.16.so
So my cross compiler is building against an older version of glibc. I've read in several places that glibc should be backwards-compatible.
I thought about static linking only libc, but according to this question it's a bad idea unless all libraries are statically linked.
Static linking everything does work, but there are serious constraints on the system which mean I need to keep the binaries as small as possible.
Any ideas what would cause horrible problems with strtod() (and similar functions) and/or why glibc 2.13 is not backwards compatible?
EDIT:
I didn't mention that the "soname" (i.e. top level name) is the same on all platforms: "libc.so.6" From my reading of the docs, the number AFTER the .so in the "soname" is the major version and only changes if the interface changes - hence all these versions should be compatible. The number BEFORE the .so which appears in the actual file name (shown above, and found by following the symlink) is the minor version. See: link
Generally version numbers reflect compatibility. The number that appears between the .so and the next dot represents a MAJOR revision, not guaranteed compatible with any other major revision.
The number(s) that that follow that, which you'll only see if you follow the symbolic links, represents a MINOR revision. These can be used interchangably, and symlinks are used to do just that. The program links against libc.so.6 or whatever, and on the actual filesystem, libc.so.6 is a symbolic link to (for example) libc.so.6.12.
glibc tries to maintain compatibility even across major revisions, but there are times when they simply have to accept a breaking change. Typically this would be when a new version of the C or POSIX standards are released and function signatures get updated in a way that breaks binary compatibility.
Any numbers that appear before the .so will also break compatibility if changed; these usually represent a complete rewrite of a program. For example glib vs glib2. Not of concern for libc.
The tool ldd is very useful for investigating library dependencies and discovering while exact version of the library is actually being loaded.

Getting weird result by using %I64u inside Mingw-w64

This is my code :
Note : \n inside scanf is my way to prevent trailing newline problem. That isn't best solution but i'm using it too much and currently it becoming my habit. :-)
...
int main()
{
unsigned long long int input[2], calc_square;
while(scanf("\n%I64u %I64u", input[0], input[1]) == 2)
{
printf("%I64u %I64u\n", input[0], input[1]);
...
My expected input and program result is :
Input :
89 89
For output, instead of printing back 89, it show this output :
I64u I64u
I'm using g++ (GCC) 4.9.1 from MSYS2 package. Noted that g++ because there are some portion of my code currently using C++ STL.
Edited : I changed my code by using standard %llu instead of %I64u, and here is my expected input and program result :
Input
89 89
For output, it's kind a weird result :
25769968512 2337536
This code is wrong:
while(scanf("\n%I64u %I64u", input[0], input[1]) == 2)
input[0] and input[1] each have type unsigned long long, but they are required to have type unsigned long long * (pointer to unsigned long long) for scanf operations. I'm unsure if MinGW supports checking printf and scanf format specifiers, but ordinary GCC is capable of detecting these kinds of errors at compile time as long as you enable the proper warnings. I highly recommend always compiling with as high of a warning level as you possibly can, such as -Wall -Wextra -Werror -pedantic in the most extreme case.
You need to pass in the address of these variables:
while(scanf("\n%I64u %I64u", &input[0], &input[1]) == 2)
// ^ ^
// | |
I suspect you have been using MSYS2's GCC which isn't a native Windows compiler, and doesn't support the MS-specific %I64 format modifiers (MSYS2's GCC is very much like Cygwin's GCC).
If you wanted to use MinGW-w64 GCC, you should have launched mingw64_shell.bat or mingw32_shell.bat and have the appropriate toolchain installed:
pacman -S mingw-w64-i686-toolchain
or
pacman -S mingw-w64-x86_64-toolchain
With that done, you can safely use either modifier on any Windows version dating back to Windows XP SP3 provided you pass -D__USE_MINGW_ANSI_STDIO=1.
FWIW, I avoid using the MS-specific modifiers and always pass -D__USE_MINGW_ANSI_STDIO=1
Finally, annoyingly, your sample doesn't work when launched from the MSYS2 shell due to mintty not being a proper Windows console; you need to run it from cmd.exe

Call C/C++ code form a fortran program in visual studio? (How to compile mixed C and fortran code in visual studio)

i am looking for a way, how i can integrate a c++ code with fortran code (i want simply call some C/C++ functions in the fortran code).
I have found some proposals for gcc or console compilers, but i have not any idea how to translate this approach to solve integrationproblem within the visual studio.
At the time I am thinking about creating a dll form c++ code and calling it from Fortran code.
Has someone already seen a solution? Or what is about overhead for calling function from dll? My fortran code transfers a lot of memory into C function, is there any problems, if i would solve this problem with dll?
thx.
PS
I am using Visual Studio 2008 Prof and Intel compilers 10
PPS
I think, i have to specify more concrete, what i want: i want to compile a fortran project in visual studio, which uses some C functions.
There is a new way to do this that has many advantages -- use the Fortran 2003 ISO C Binding. This is a standard and therefore largely OS and language independent way of interfacing Fortran and C (and any language that will use C calling conventions). Intel Fortran 11 supports along with numerous other compilers -- not sure about version 10. Using the ISO C Binding, you can match any C name (any case), don't have to worry about underscores (and variations between compilers) and can specify the types and calling methods (by reference, by value) for the arguments. Intel provides some examples in a folder with their compiler; there are also examples in the gfortran manual and a discussion of additional considerations for Windows. There are previous questions & answers here and on the Intel Fortran forum.
I integrated C and Fortran about 20 years ago and maintained this integration up to 5 years ago. The tricks I used were:
I noticed that the Fortran compiler puts all symbols in uppercase, so make sure your C/C++ functions are written in uppercase as well. To verify how symbols are put in the .OBJ file, use DUMPBIN.
The Fortran compiler does not understand the name-mangling done by the C++ compiler. Compile all your C++ functions using the C style convention (using extern "C")
Arguments in Fortran are always put on the stack using references/pointers. Therefore, use pointer-arguments in your C function.
To be honest, I gave up integrating C and Fortran when I switched to VS2005, so things might have changed since then. Nevertheless, it's still a good idea to use DUMPBIN to see what kind of symbols the Fortran compiler produces, and adjust the compilation of C/C++ sources to fit with that.
We do it where I work.
Assuming you are using the Intel Fortran compiler, look up its docs. By default Intel Fortran passes everything by reference and (I believe) uses the C calling convention, with an all caps identifier. Strings are a particular issue, as Fortran likes to pass the length as a hidden parameter, with a compiler setting for where it goes in the parameter list.
A wise programer doesn't rely on defaults (where a mistake can lead to undefined behavior), and will use the intel INTERFACE statements to specify calling convention, parameter passing, and the link name for the routine. The information on this page (ATTRIBUTES Properties and Calling Conventions) is a must-read. In particular you need it to understand the arcane rules for when and where string length parameters will be passed. I have a printout of it that I keep on my person. :-)
One other thing to note is that versions of VisualStudio past 6 don't like mixed Fortran and C projects. We solved the problem by creating custom project files calling out to makefile, but that's a PITA. I'd suggest going with the flow and using separate projects unless you are doing this a lot like we are.
Solution found:
solution link
i have had several problem with linking, which could be solved with adding in project properties.
code for testing:
#include <stdio.h>
extern "C"
{
void f()
{
printf("hi from c\n mega test");
}
}
fortran code
PROGRAM HelloWorld
use, intrinsic :: iso_c_binding
implicit none
interface
subroutine f( ) bind( c )
use, intrinsic :: iso_c_binding
end subroutine f
end interface
call f
END PROGRAM HelloWorld
on demand i can upload the testproject. thanks all, hopefully it was my last problem with c and fortran
I was able to build obj from fortran sources thanks to the Custom Build Tools of Visual Express 2010. I guess it is also possible in Visual Studio.
If you want to mix C and Fortran together, there is a good tutorial here. It was written for gcc compilers but you should be able to learn how to deal with name mangling easily.
Depending on the compiler, compiled subroutines/functions are Uppercase/lowercase, with a trailing underscore, with a leading underscore,... For a succesfull linkage, you could use dumpbin tools to see how the name appears in the objectfile.
An other way is to use iso_c_binding modules, but it is available with Fortran 2003 only.
This is the how it works with gcc and console
c.c:
#include <stdio.h>
void f_()
{
printf("Hi from C\n");
}
fortran.f90
PROGRAM HelloWorld
CALL f
END PROGRAM HelloWorld
Makefile
SRCDIR=.
all: clean release run
release:
gcc -c c.c -o c.out
gfortran -c fortran.f90 -o fortran.out
gfortran -o out.exe fortran.out c.out
run:
out.exe
clean:
#$(ZSHMAGIC) rm -rf *.exe core* *.o a.out 2> /dev/null
One other question: have i always add '_' after c-function name, which i use in the fortran program?