On Wednesday, June 22, 2016 at 9:47:58 PM UTC+7, Alessandro wrote:
> From a point of view of computational efficiency is there any significant different using an IF/ELSEIF... structure rather that a SELECT CASE one...?
Dear Dick,
Thank you for pointing out the bug :D It was my mistake. Yes, it should be like this:
key = mod(i,10) + 1
Now it becomes
key = int(mod(i,10),kind=4) + 1
for i,N integer 8 bytes. So we can run the test with huge values of N. (See new version of the test at the bottom of this post)
I run the test for 4 cases:
+ 2 cases for ifort 18.0 with/without optimization (-O3), and
+ 2 cases for gfortran 4.9.2 with/without optimization (-O3).
In addition, there is some changes on the labels:
+ F77-GOTO was GOTO (in the old version)
+ SELECT-CASE was SELECT CASE (in the old version)
+ IF-Goto1 was IF-Goto (in the old version)
+ IF-Goto2 was IF-noGoto (in the old version)
+ IF-ELSE remains the same.
Here is the output:
Case 1) ifort -O3 test_v02.f90
./a.out 100000000 300000000 500000000 700000000 900000000
Number of input arguments: 5
F77-GOTO: N = 100000000, ss = 0.4321400E+10, time = 0.380 (s)
SELECT-CASE: N = 100000000, ss = 0.4321400E+10, time = 0.812 (s)
IF-Goto1: N = 100000000, ss = 0.4321400E+10, time = 0.480 (s)
IF-Goto2: N = 100000000, ss = 0.4321400E+10, time = 0.468 (s)
IF-ELSE: N = 100000000, ss = 0.4321400E+10, time = 0.924 (s)
F77-GOTO: N = 300000000, ss = 0.1296420E+11, time = 1.104 (s)
SELECT-CASE: N = 300000000, ss = 0.1296420E+11, time = 2.288 (s)
IF-Goto1: N = 300000000, ss = 0.1296420E+11, time = 1.444 (s)
IF-Goto2: N = 300000000, ss = 0.1296420E+11, time = 1.408 (s)
IF-ELSE: N = 300000000, ss = 0.1296420E+11, time = 2.736 (s)
F77-GOTO: N = 500000000, ss = 0.2160700E+11, time = 1.840 (s)
SELECT-CASE: N = 500000000, ss = 0.2160700E+11, time = 3.812 (s)
IF-Goto1: N = 500000000, ss = 0.2160700E+11, time = 2.400 (s)
IF-Goto2: N = 500000000, ss = 0.2160700E+11, time = 2.352 (s)
IF-ELSE: N = 500000000, ss = 0.2160700E+11, time = 4.580 (s)
F77-GOTO: N = 700000000, ss = 0.3024980E+11, time = 2.580 (s)
SELECT-CASE: N = 700000000, ss = 0.3024980E+11, time = 5.324 (s)
IF-Goto1: N = 700000000, ss = 0.3024980E+11, time = 3.356 (s)
IF-Goto2: N = 700000000, ss = 0.3024980E+11, time = 3.288 (s)
IF-ELSE: N = 700000000, ss = 0.3024980E+11, time = 6.432 (s)
F77-GOTO: N = 900000000, ss = 0.3889260E+11, time = 3.312 (s)
SELECT-CASE: N = 900000000, ss = 0.3889260E+11, time = 6.920 (s)
IF-Goto1: N = 900000000, ss = 0.3889260E+11, time = 4.316 (s)
IF-Goto2: N = 900000000, ss = 0.3889260E+11, time = 4.208 (s)
IF-ELSE: N = 900000000, ss = 0.3889260E+11, time = 8.272 (s)
F77-GOTO costs totally 9.216 (s)
SELECT-CASE costs totally 19.156 (s)
IF-Goto1 costs totally 11.996 (s)
IF-Goto2 costs totally 11.724 (s)
IF-ELSE costs totally 22.944 (s)
Total time: 75.036 (s)
----------------------------------------------------------------------
Case 2) ifort test_v02.f90
./a.out 100000000 300000000 500000000 700000000 900000000
Number of input arguments: 5
F77-GOTO: N = 100000000, ss = 0.4321400E+10, time = 0.368 (s)
SELECT-CASE: N = 100000000, ss = 0.4321400E+10, time = 0.764 (s)
IF-Goto1: N = 100000000, ss = 0.4321400E+10, time = 0.484 (s)
IF-Goto2: N = 100000000, ss = 0.4321400E+10, time = 0.468 (s)
IF-ELSE: N = 100000000, ss = 0.4321400E+10, time = 0.912 (s)
F77-GOTO: N = 300000000, ss = 0.1296420E+11, time = 1.108 (s)
SELECT-CASE: N = 300000000, ss = 0.1296420E+11, time = 2.288 (s)
IF-Goto1: N = 300000000, ss = 0.1296420E+11, time = 1.444 (s)
IF-Goto2: N = 300000000, ss = 0.1296420E+11, time = 1.408 (s)
IF-ELSE: N = 300000000, ss = 0.1296420E+11, time = 2.744 (s)
F77-GOTO: N = 500000000, ss = 0.2160700E+11, time = 1.852 (s)
SELECT-CASE: N = 500000000, ss = 0.2160700E+11, time = 3.828 (s)
IF-Goto1: N = 500000000, ss = 0.2160700E+11, time = 2.400 (s)
IF-Goto2: N = 500000000, ss = 0.2160700E+11, time = 2.340 (s)
IF-ELSE: N = 500000000, ss = 0.2160700E+11, time = 4.580 (s)
F77-GOTO: N = 700000000, ss = 0.3024980E+11, time = 2.576 (s)
SELECT-CASE: N = 700000000, ss = 0.3024980E+11, time = 5.360 (s)
IF-Goto1: N = 700000000, ss = 0.3024980E+11, time = 3.536 (s)
IF-Goto2: N = 700000000, ss = 0.3024980E+11, time = 3.276 (s)
IF-ELSE: N = 700000000, ss = 0.3024980E+11, time = 6.468 (s)
F77-GOTO: N = 900000000, ss = 0.3889260E+11, time = 3.316 (s)
SELECT-CASE: N = 900000000, ss = 0.3889260E+11, time = 6.860 (s)
IF-Goto1: N = 900000000, ss = 0.3889260E+11, time = 4.320 (s)
IF-Goto2: N = 900000000, ss = 0.3889260E+11, time = 4.228 (s)
IF-ELSE: N = 900000000, ss = 0.3889260E+11, time = 8.272 (s)
F77-GOTO costs totally 9.220 (s)
SELECT-CASE costs totally 19.100 (s)
IF-Goto1 costs totally 12.184 (s)
IF-Goto2 costs totally 11.720 (s)
IF-ELSE costs totally 22.976 (s)
Total time: 75.200 (s)
----------------------------------------------------------------------
Case 3) gfortran -O3 test_v02.f90
./a.out 100000000 300000000 500000000 700000000 900000000
Number of input arguments: 5
F77-GOTO: N = 100000000, ss = 0.4321400E+10, time = 0.956 (s)
SELECT-CASE: N = 100000000, ss = 0.4321400E+10, time = 0.896 (s)
IF-Goto1: N = 100000000, ss = 0.4321400E+10, time = 0.436 (s)
IF-Goto2: N = 100000000, ss = 0.4321400E+10, time = 0.440 (s)
IF-ELSE: N = 100000000, ss = 0.4321400E+10, time = 0.440 (s)
F77-GOTO: N = 300000000, ss = 0.1296420E+11, time = 2.836 (s)
SELECT-CASE: N = 300000000, ss = 0.1296420E+11, time = 2.688 (s)
IF-Goto1: N = 300000000, ss = 0.1296420E+11, time = 1.316 (s)
IF-Goto2: N = 300000000, ss = 0.1296420E+11, time = 1.320 (s)
IF-ELSE: N = 300000000, ss = 0.1296420E+11, time = 1.320 (s)
F77-GOTO: N = 500000000, ss = 0.2160700E+11, time = 4.748 (s)
SELECT-CASE: N = 500000000, ss = 0.2160700E+11, time = 4.500 (s)
IF-Goto1: N = 500000000, ss = 0.2160700E+11, time = 2.304 (s)
IF-Goto2: N = 500000000, ss = 0.2160700E+11, time = 2.400 (s)
IF-ELSE: N = 500000000, ss = 0.2160700E+11, time = 2.624 (s)
F77-GOTO: N = 700000000, ss = 0.3024980E+11, time = 7.096 (s)
SELECT-CASE: N = 700000000, ss = 0.3024980E+11, time = 6.356 (s)
IF-Goto1: N = 700000000, ss = 0.3024980E+11, time = 3.104 (s)
IF-Goto2: N = 700000000, ss = 0.3024980E+11, time = 3.136 (s)
IF-ELSE: N = 700000000, ss = 0.3024980E+11, time = 3.100 (s)
F77-GOTO: N = 900000000, ss = 0.3889260E+11, time = 8.704 (s)
SELECT-CASE: N = 900000000, ss = 0.3889260E+11, time = 8.228 (s)
IF-Goto1: N = 900000000, ss = 0.3889260E+11, time = 4.060 (s)
IF-Goto2: N = 900000000, ss = 0.3889260E+11, time = 4.012 (s)
IF-ELSE: N = 900000000, ss = 0.3889260E+11, time = 4.000 (s)
F77-GOTO costs totally 24.340 (s)
SELECT-CASE costs totally 22.668 (s)
IF-Goto1 costs totally 11.220 (s)
IF-Goto2 costs totally 11.308 (s)
IF-ELSE costs totally 11.484 (s)
Total time: 81.020 (s)
----------------------------------------------------------------------
Case 4) gfortran test_v02.f90
./a.out 100000000 300000000 500000000 700000000 900000000
Number of input arguments: 5
F77-GOTO: N = 100000000, ss = 0.4321400E+10, time = 2.972 (s)
SELECT-CASE: N = 100000000, ss = 0.4321400E+10, time = 2.980 (s)
IF-Goto1: N = 100000000, ss = 0.4321400E+10, time = 3.076 (s)
IF-Goto2: N = 100000000, ss = 0.4321400E+10, time = 3.088 (s)
IF-ELSE: N = 100000000, ss = 0.4321400E+10, time = 3.100 (s)
F77-GOTO: N = 300000000, ss = 0.1296420E+11, time = 9.556 (s)
SELECT-CASE: N = 300000000, ss = 0.1296420E+11, time = 9.020 (s)
IF-Goto1: N = 300000000, ss = 0.1296420E+11, time = 9.368 (s)
IF-Goto2: N = 300000000, ss = 0.1296420E+11, time = 9.452 (s)
IF-ELSE: N = 300000000, ss = 0.1296420E+11, time = 9.288 (s)
F77-GOTO: N = 500000000, ss = 0.2160700E+11, time = 14.940 (s)
SELECT-CASE: N = 500000000, ss = 0.2160700E+11, time = 14.920 (s)
IF-Goto1: N = 500000000, ss = 0.2160700E+11, time = 15.484 (s)
IF-Goto2: N = 500000000, ss = 0.2160700E+11, time = 15.524 (s)
IF-ELSE: N = 500000000, ss = 0.2160700E+11, time = 15.364 (s)
F77-GOTO: N = 700000000, ss = 0.3024980E+11, time = 20.884 (s)
SELECT-CASE: N = 700000000, ss = 0.3024980E+11, time = 20.852 (s)
IF-Goto1: N = 700000000, ss = 0.3024980E+11, time = 21.740 (s)
IF-Goto2: N = 700000000, ss = 0.3024980E+11, time = 21.776 (s)
IF-ELSE: N = 700000000, ss = 0.3024980E+11, time = 21.392 (s)
F77-GOTO: N = 900000000, ss = 0.3889260E+11, time = 26.920 (s)
SELECT-CASE: N = 900000000, ss = 0.3889260E+11, time = 26.820 (s)
IF-Goto1: N = 900000000, ss = 0.3889260E+11, time = 27.760 (s)
IF-Goto2: N = 900000000, ss = 0.3889260E+11, time = 27.940 (s)
IF-ELSE: N = 900000000, ss = 0.3889260E+11, time = 27.668 (s)
F77-GOTO costs totally 75.272 (s)
SELECT-CASE costs totally 74.592 (s)
IF-Goto1 costs totally 77.428 (s)
IF-Goto2 costs totally 77.780 (s)
IF-ELSE costs totally 76.812 (s)
Total time: 381.884 (s)
----------------------------------------------------------------------
Here are the compilers:
$ gfortran -v
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10)
$ ifort -v
ifort version 18.0.0
Here is the "test_v02.f90":
!--------------------------------------------------------------------
!
! This test shows a proof that codes using the SELECT-CASE inside
! a huge loop may run much slower than using the IF-THEN. It also
! shows that codes using the 'obsolete' computed GOTO (F77) can
! run extremely fast in the circumstance when compiling with Intel
! compiler. The GOTO (F77) is the fastest one with Ifort (with or
! without -O3), but it turns to the worst with Gfortran (with -O3).
!
! Changes: (from the last post)
!
! + integer*8 N ---> integer N, so that N can get huge value.
!
! + key = int(mod(i,ten),kind=4) + 1 ---> key = mod(N,10) + 1
! (based on suggestion of Dick Hendrickson from comp.lang.fortran)
!
! + 1 format( ... i12 ... ) ---> 1 format( ... i9 ... )
!
! Labels changed:
! + 'F77-GOTO' ---> 'GOTO' in the old version
! + 'SELECT-CASE' ---> 'SELECT CASE' in the old version
! + 'IF-Goto1' ---> 'IF-Goto' in the old version
! + 'IF-Goto2' ---> 'IF-noGoto' in the old version
! + 'IF-ELSE' remains the same.
!
!
program tt_goto_02
implicit none
double precision x1, x2, ss, st1, st2, st3, st4, st5
real t1, t2, dt1, dt2, dt3, dt4, dt5
integer*8 N, ten, i
integer j, key, narg
character(len=15) charg
!
! USAGE:
!
! Compiling:
! ifort -O3 tt_goto_01.f90
! or
! gfortran -O3 tt_goto_01.f90
!
! Executing:
! ./a.out 100000000 200000000 300000000
! or
! ./a.out 1000000000 2000000000 3000000000 7000000000
!
! wherein the loop size N will be read serially. We can input more.
!
st1 = 0.0d0
st2 = 0.0d0
st3 = 0.0d0
st4 = 0.0d0
!
ten = 10
!
narg = command_argument_count()
write(*,*) 'Number of input arguments: ', narg
!
! Loop over arguments input from command-line:
! narg: the total number of arguments.
!
DO 999 j = 1,narg
!
charg = ''
call get_command_argument( j, charg )
!
! Reading the value of N from command-line:
!
read(charg,*) N
!
if ( N < 1 ) stop
!
!
! 1) Testing Computed GOTO: named 'F77-GOTO'
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0
call cpu_time (t1)
do i = 1,N
key = int(mod(i,ten),kind=4) + 1
write(*,1) 'F77-GOTO:', N, ss, dt1
!
!
! 2) Testing SELECT CASE: named 'SELECT-CASE'
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0
call cpu_time (t1)
do i = 1,N
key = int(mod(i,ten),kind=4) + 1
write(*,1) 'SELECT-CASE:', N, ss, dt2
!
!
! 3) Testing IF with Goto: named 'IF-Goto1'
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0
call cpu_time (t1)
do i = 1,N
key = int(mod(i,ten),kind=4) + 1
write(*,1) 'IF-Goto1:', N, ss, dt3
!
!
! 4) Testing IF with less Goto's: named 'IF-Goto2'
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0
call cpu_time (t1)
do i = 1,N
key = int(mod(i,ten),kind=4) + 1
!
enddo
call cpu_time (t2)
dt4 = t2 - t1
st4 = st4 + dt4
write(*,1) 'IF-Goto2:', N, ss, dt4
!
!
! 5) Testing IF/ELSE: named 'IF-ELSE'
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0
call cpu_time (t1)
do i = 1,N
key = int(mod(i,ten),kind=4) + 1
write(*,1) 'IF-ELSE:', N, ss, dt5
!
!
write(*,*)
!
999 CONTINUE
!
! Finally reporting the result:
!
write(*,3) 'F77-GOTO', st1
write(*,3) 'SELECT-CASE', st2
write(*,3) 'IF-Goto1', st3
write(*,3) 'IF-Goto2', st4
write(*,3) 'IF-ELSE', st5
write(*,4) 'Total time:', st1 + st2 + st3 + st4 + st5
!
! Format section:
!
1 format( a15, 1x, 'N =', i12, ', ss =', e14.7, &
', time = ', f8.3, ' (s)')
3 format( a15, 1x, 'costs totally ',1x, f8.3, ' (s)')
4 format( a15, 1x, f8.3, ' (s)', /, 70('-') )
!
stop
end program
!--------------------------------------------------------------------