Rahn
Rahn

Reputation: 5425

ifort and gfortran get different results computing acos(x)

I'm compiling a simple fortran program with gfortran and ifort:

! acos.f90
function real8_to_int8(real8) result(int8)
    real(8), intent (in) :: real8
    integer(8) :: int8
    int8 = transfer(real8, int8)
end function

function int8_to_real8(int8) result(real8)
    integer(8), intent (in) :: int8
    real(8) :: real8
    real8 = transfer(int8, real8)
end function

program main
    integer(8) :: real8_to_int8
    real(8) :: int8_to_real8
    real :: x, acos_x

    x = int8_to_real8(4605852290655121993)

    print *, " size of x: ", sizeof(x)
    write (*, '(A, F65.60)') ' x: ', x
    print *, ""

    acos_x = acos(x)

    write (*, '(A, F65.60)') ' acos(x): ', acos(x)
    print *, "bits:     ", real8_to_int8(acos_x)
    print *, ""
    print *, ""
end program

To compare the results as precisely as possible, I print out the variables' bit representations, and they are different:

ifort: 
$ ifort -real-size 64 -o acos_ifort acos.f90; ./acos_ifort

  size of x:                      8
 x:    0.852326110783516388558211929193930700421000000000000000000000
 
 acos(x):    0.550379481046229246388179490168113261461000000000000000000000
 bits:        4603132597196780746
gfortran:
$ gfortran -fdefault-integer-8 -fdefault-real-8 -o acos_gfortran acos.f90; ./acos_gfortran

  size of x:                     8
 x:    0.852326110783516388558211929193930700421333312988281250000000
 
 acos(x):    0.550379481046229357410481952683767303824424743652343750000000
 bits:       4603132597196780747

Is the difference on variable acos(x) normal? Or how can I change my gfortran compiling option to make the result of gfortran the same as ifortran?

ifort:
 acos(x):    0.550379481046229246388179490168113261461000000000000000000000
 bits:       4603132597196780746

gfortran:
 acos(x):    0.550379481046229357410481952683767303824424743652343750000000
 bits:       4603132597196780747

Upvotes: 1

Views: 204

Answers (1)

janneb
janneb

Reputation: 37248

Yes, the difference in angle is normal. You cannot generally assume different implementations of the trigonometrical functions to produce bit-exact results. As you can see from the integer representation there's only a 1 ulp difference between the two values, which is entirely reasonable.

EDIT And as a standards-conformance and style issue, here's a version of your code with

  • use int64 and real64 from the iso_fortran_env builtin module instead of the non-portable kind=8.
  • Put the functions as contained procedures to get explicit interface checking (although in this case it's a bit pointless as one could just as well call transfer directly, but just to demonstrate usage of contained procedures).
  • Use kind values appropriately including on the big literal to avoid the need for -fdefault-real-8 and similar options.

! acos.f90
program main
  use iso_fortran_env
  real(real64) :: x, acos_x

  x = int8_to_real8(4605852290655121993_int64)

  print *, " size of x: ", sizeof(x)
  write (*, '(A, F65.60)') ' x: ', x
  print *, "" 

  acos_x = acos(x)

  write (*, '(A, F65.60)') ' acos(x): ', acos(x)
  print *, "bits:     ", real8_to_int8(acos_x)
  print *, ""
  print *, ""

contains
  function real8_to_int8(real8) result(int8)
    real(real64), intent (in) :: real8
    integer(int64) :: int8
    int8 = transfer(real8, int8)
  end function

  function int8_to_real8(int8) result(real8)
    integer(int64), intent (in) :: int8
    real(real64) :: real8
    real8 = transfer(int8, real8)
  end function

end program

Upvotes: 3

Related Questions