Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28592 Discussions

Alternatives instead of "if ... else" to speed up code

Wee_Beng_T_
Beginner
385 Views
Hi,
In my codes there's a lot of "if..else" statements. I'm told that they tend to slow down codes.
So I'm thinking of other alternatives, like the one below:
The 1st subroutineif_elseuses the "if...else" statement but the 2nd if_else2 does some arithimetics to avoid that.
I tested the runtime but they are almost the same, both in debug and optimized mode. Does this mean it makes no difference whether "if..else" is used?
Thanks!
program if_else_test
!test whether if_else can be avoided
implicit none
integer,parameter :: loop_no=10000,size=10000,call_time=20000
integer :: i
real :: array(size)
do i=1,call_time
call if_else2(loop_no,size,array) !or call if_else(loop_no,size,array)
end do
contains
subroutine if_else(loop_no,size,array)
!use if...else
integer, intent(in) :: loop_no,size
integer :: w(size)
real :: u(size),v(size)
real, intent(inout) :: array(size)
do i=1,loop_no
call random_number(u(i)); call random_number(v(i))
w(i)=(u(i)-v(i))/abs(u(i)-v(i))
if (w(i)==1) then
array(i)=2.*u(i)
else if (w(i)==-1) then
array(i)=2.*v(i)
end if
end do
end subroutine if_else
subroutine if_else2(loop_no,size,array)
!use alternative
integer, intent(in) :: loop_no,size
integer :: w(size)
real :: u(size),v(size)
real, intent(inout) :: array(size)
do i=1,loop_no
call random_number(u(i)); call random_number(v(i))
w(i)=(u(i)-v(i))/abs(u(i)-v(i))
array(i)= (w(i)+1)*u(i) - (w(i)-1)*v(i)
end do
end subroutine if_else2
end program if_else_test
0 Kudos
4 Replies
tom_p
Beginner
385 Views
I would suggest something like this (untested):

[fortran]subroutine if_else(loop_no, size, array)
  integer, intent(in) :: loop_no, size
  real, intent(out) :: array(size)
  integer :: i
  real :: u, v

  do i = 1, loop_no
    call random_number(u)
    call random_number(v)
    array(i) = 2*max(u, v)
  end do
end subroutine if_else
[/fortran]

I think this is easier to understand and does not suffer from potential floating point rounding errors as the original code does (there is no guarantee w(i) will be exactly equal to 1 or -1, and abs(u(i)-v(i)) could be zero).

However, I would not expect a large difference in speed. The biggest impact could, I guess, be achieved by using a different random number generator that is adapted to your problem (fast, but still "random" enough).
0 Kudos
TimP
Honored Contributor III
385 Views
Performance impact of if..else is more significant when it affects auto-vectorization. As you call a serial random number generator, the impact of the if..else would be relatively small here.
As the preceding response hinted, a selection by max() (or by an if which the compiler recognizes as equivalent) would be vectorizable in the absense of the subroutine call.
0 Kudos
Wee_Beng_T_
Beginner
385 Views
Thanks Tom_p and TimP!
Well, I'm actually giving an example. In my e.g., I am trying to use :
array(i) = (w(i)+1)*u(i) - (w(i)-1)*v(i)
instead of
if (w(i)==1) then
array(i)=2.*u(i)
else if (w(i)==-1) then
array(i)=2.*v(i)
end if
The 1st case uses more operations but it avoids the use of "if..else".
Hence I wonder if the 1st case is better? Especially when optimizations are enabled.
0 Kudos
Steven_L_Intel1
Employee
385 Views
Don't forget that RANDOM_NUMBER can take an array argument to get many at once.
0 Kudos
Reply