precision in pgf90?

i am running/compiling the same piece of software on two different machine and getting slightly different results. I am assuming this is due to precision issues, but have not been able to figure out how to change the compile options, so I will get the same result on both. One machine is running 32bit Redhat 9 with an athlon mp processor. The other is running 64bit CentOS 4.3 or 4.4 with an amd opteron processor. Any body know how I can compile the code on the machines and get the exact same results?

Hi echorak,

You’re most likely encountering differences between using the 80-bit x87 FPU on your AthlonMP and 64-bit SSE FPU on your Opteron. For rmore detailed information about this topic please refer to the PGI FAQ page.

If you don’t mind sacrificing some perfomance, you can use the “-Kieee” flag. “-Kieee” tells the compiler to maintain strict IEEE 754 floating point accuracy conformance and should give you more consistant results. However, this is a big hammer so you should consider performance vs consistancy trade-offs before using it.

  • Mat

I’ll chime in here and mention that there are currently four floating point precisions that are commonly used with IEEE 754.

Single (real4), 32-bit (24 bit mantissa, epsilon about 1.2e-07)
Double (real
8), 64-bit (53 bit mantissa, epsilon about 2.2e-16)
Extended (no corresponding Fortran type), 80-bit (64 bit mantissa, epsilon about 1.1e-19)
Quad (real*16) (113 bit mantissa, epsilon about 1.9e-34)

The internal registers of the 8087 FPU use the extended format. You can sometimes see anomalies when the precision of the internal FPU registers exceeds the precision of the variables in memory, especially with optimization which will skip intermediate loads and stores at reduced precision.

Here’s an example code that tries to guess machine epsilon and then exhibits it using the epsilon(1.0) intrinsic. If you compile it with “-r4 -O0” and then again with “-r4 -O2”, you’ll get two different results. So part of your problem might also be different optimizations when targetting the different CPUs.

program machine_epsilon
  implicit none
  integer, parameter :: rk = kind(1.0)
  real(kind=rk) :: eps, q
  real(kind=rk), parameter :: one = 1.0, two = 2.0
  integer :: prec, j
  character, dimension(rk) :: bits
  equivalence(q, bits)

  q = one + one/two ! Keep q near one to avoid denormalized numbers.
  prec = 2 ! There are two bits in q right now: 1 and 0.5.
     write (*, '(i4,f15.12)', advance='no') prec, q
     write (*, '(1x,24z2.2)', advance='no') (bits(j), j=rk,1,-1) !little-endian
     write (*, '(1x)')
     eps = q - one
     q = one + eps/two ! move one binary point to the right.
     if (q .eq. one) exit
     prec = prec + 1
  end do

  write (*, '("kind =",i3," bits =",i4," epsilon =",es)'), rk, prec, eps

  write (*, '("kind =",i3," bits =",i4," epsilon =",es)') kind(one), digits(one), epsilon(one)
end program machine_epsilon

Thank you for your check-code.
But, when I run it, I found next result.
How can I modify it?

Thank you again.

21 1.000000953674 3F800008
22 1.000000476837 3F800004
23 1.000000238419 3F800002
24 1.000000119209 3F800001
PGFIO-F-249/formatted write/unit=6/error in format - illegal E, F, G or D descriptor.
File name = stdout formatted, sequential access record = 70
In source file check.f, at line number 23

Change the edit descriptor from “es” to “es10.3”.

  • Mat