glen herrmannsfeldt wrote:
> James <
james.s...@gmail.com> wrote:
>
>> A key bottleneck in a code I work on is the evaluation of
>> exp(ix) inside a tight loop. This can be evaluated using
>> either exp(cmplx(0.0,x)) or cmplx(cos(x),sin(x)): both
>> approaches should be equivalent. However, I have found
>> that gfortran and ifort treat these constructs very differently.
>
> Besides the question on the KIND of CMPLX, and besides the usual
> comments on premature optimization, I would use the second form.
I tried amalgamating the OP's 2 programs, using a third method inside the
loop, fixing the CMPLX problem, and also calculating a geometric progression
instead of using pseudorandom numbers so the "exact" (really quad precision)
mathematical result could be compared with the computed results. I used
ifort Version 12.1 Build 20120212 and gfortran version 4.7.1 on the same
Linux x86_64 machine. It seems that gfortran's arithmetic can give different
answers with different optimisation levels, that with the -Ofast option it
was faster _for this program_ than ifort (I have had ifort twice as fast as
gfortran when dealing with lots of double precision real arrays), and that
the speed varies with the algorithm (surprise surprise). Using ifort -O2
made no difference to the results and at most 0.025 seconds to the time in a
program taking it 8 or 11 seconds. FWIW gfortran compiled much faster than
ifort: useful when trying possibilities, unimportant for production.
The program:
program test_exp_cos_sin
implicit none
complex(selected_real_kind(33)) :: iquad = (0,1), w
character(*),parameter:: fmt = "(' (',F21.18,',',F21.18,' ) ',A)"
integer,parameter :: ilast = 10**8
character(7) time
call timing(1)
call timing(2)
call timing(3)
w = exp(iquad)
write (6,fmt) w*(1-w**ilast)/(1-w),'"exact"'
contains
subroutine timing(iwhich)
integer,intent(in) :: iwhich
integer, parameter :: dp = selected_real_kind(15,307)
complex(dp),parameter :: dpi = (0._dp, 1._dp)
complex(dp) :: s
real(dp) :: x
integer :: i
real :: start, finish
s = cmplx(0.0_dp, 0.0_dp)
x = 0.0_dp
call cpu_time(start)
do i = 1,ilast
x = x + 1.0_dp
if (iwhich==1) then
s = s + exp( dpi*x )
else if (iwhich==2) then
s = s + exp(cmplx(0.0_dp,x,dp))
else
s = s + cmplx(cos(x),sin(x),dp)
end if
end do
call cpu_time(finish)
write(time,"(F7.3)") finish-start
write (6,fmt) s, time
end subroutine timing
end program test_exp_cos_sin
Output with ifort:
( 0.170984355418128453, 1.713649346570515153 ) 11.015
( 0.170984355418128453, 1.713649346570515153 ) 8.026
( 0.170984355418128453, 1.713649346570515153 ) 8.013
( 0.170984355418398518, 1.713649346570575846 ) "exact"
Output with gfortran (no options requested):
( 0.170984355418201228, 1.713649346570279786 ) 13.416
( 0.170984355418201228, 1.713649346570279786 ) 5.879
( 0.170984355417932610, 1.713649346570545795 ) 43.033
( 0.170984355418398518, 1.713649346570575846 ) "exact"
Output with gfortran -Ofast:
( 0.170984355418201228, 1.713649346570279786 ) 5.548
( 0.170984355418201228, 1.713649346570279786 ) 5.554
( 0.170984355418201228, 1.713649346570279786 ) 5.458
( 0.170984355418398518, 1.713649346570575846 ) "exact"
--
John Harper