Hi jockel,
Or does anyone know compiler flags for ifort, gfortran and PGI that should make use of the same floating point arithmetic and lead to the same results?
There could be a number of things going on here so I decided to write up my own little test case and was able to recreate your results:
% cat test1.f90
program testprec
real(8) :: rhov2, e_ltnt, etrans, vib_en, erot, etfun
rhov2= 0.4246880000000000109E+04_8
e_ltnt=-0.1281190399897235288E+02_8
etrans=0.3774588278644195327E+01_8
vib_en=0.8256235492705331022E-04_8
erot=0.2516391330176059871E+01_8
etfun = .5d0 * rhoV2 &
+ e_ltnt &
+ etrans &
+ vib_en &
+ erot
WRITE(*,'(e26.19)') etfun
end program testprec
% pgfortran -O0 test1.f90 -o pgi.out
% ifort -O0 test1.f90 -o intel.out
% pgi.out
0.2116919158172202970E+04
% intel.out
0.2116919158172203424E+04
Since you’re not using optimization, it narrows down the possible differences. You can try setting each compilers IEEE754 precision flag (PGI: -Kieee Intel: -fp=model precise) but it doesn’t matter here. Hence, I took a look at the assembly code (PGI: -Mkeepsam -Manno or -S, Intel: -S )
PGI:
## etfun = .5d0 * rhoV2 &
## + e_ltnt &
## + etrans &
## + vib_en &
## + erot
vaddsd %xmm3, %xmm2, %xmm2 ! etrans = vib_en+etrans
vaddsd %xmm4, %xmm2, %xmm2 ! etrans = erot + etrans
vmulsd .C1_294(%rip), %xmm0, %xmm0 ! rhoV2 = rhoV2 * 0.5d
vaddsd %xmm1, %xmm0, %xmm0 ! rhoV2 = rhoV2 + e_ltnt
vaddsd %xmm0, %xmm2, %xmm0 ! rhoV2 = rhoV2 + etrans
vmovsd %xmm0, -8(%rbp) ! etfun = rhoV2
## lineno: 17
Intel:
mulsd %xmm1, %xmm0 #11.21 ! rhoV2 = rhoV2*0.5
movsd -136(%rbp), %xmm1 #11.21 ! get e_ltnt
addsd %xmm1, %xmm0 #12.12 ! rhoV2 = rhoV2+ e_ltnt
movsd -128(%rbp), %xmm1 #12.12 ! get etrans
addsd %xmm1, %xmm0 #13.12 ! rhoV2 = rhoV2 + etrans
movsd -120(%rbp), %xmm1 #13.12 ! get vib_en
addsd %xmm1, %xmm0 #14.12 ! rhoV2 = rhoV2 + vib_en
movsd -112(%rbp), %xmm1 #14.12 ! get erot
addsd %xmm1, %xmm0 #11.8 ! rhoV2 = rhoV2 + erot
movsd %xmm0, -104(%rbp) #11.8 ! etfun = rhoV2
PGI and Intel are evaluating your expression in different orders. PGI tends to go from right to left, while Intel goes from left to right. The difference in the order of operations is causing difference. Both are correct since both adhere to operator precedence and associativity, just a different correct.
To make them agree, you need to force the compilers to evaluate the expression in the same way by using parentheses.
% cat test2.f90
program testprec
real(8) :: rhov2, e_ltnt, etrans, vib_en, erot, etfun
rhov2= 0.4246880000000000109E+04_8
e_ltnt=-0.1281190399897235288E+02_8
etrans=0.3774588278644195327E+01_8
vib_en=0.8256235492705331022E-04_8
erot=0.2516391330176059871E+01_8
etfun = ((((.5d0 * rhoV2) &
+ e_ltnt) &
+ etrans) &
+ vib_en) &
+ erot
WRITE(*,'(e26.19)') etfun
end program testprec
% ifort -O0 test2.f90 -o intel2.out
% pgfortran -O0 test2.f90 -o pgi2.out
% pgi2.out
0.2116919158172203424E+04
% intel2.out
0.2116919158172203424E+04
Hope this helps,
Mat