Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

IF/ELSEIF vs. SELECT CASE

1,835 views
Skip to first unread message

Alessandro

unread,
Jun 22, 2016, 10:47:58 AM6/22/16
to

From a point of view of computational efficiency is there any significant different using an IF/ELSEIF... structure rather that a SELECT CASE one...?


Tim Prince

unread,
Jun 22, 2016, 12:11:49 PM6/22/16
to
On 6/22/2016 10:47 AM, 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...?
>
>
Impossible to answer without qualifications.

With many compilers, either could favor the first branch, or, with
profile feedback, the one most frequently executed in the training suite.

In a recent case where we wanted all branches favored as equally as
possible, we resorted to computed goto.

michael...@compuserve.com

unread,
Jun 22, 2016, 12:20:30 PM6/22/16
to
On Wednesday, 22 June 2016 16:47:58 UTC+2, 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...?

A case statement depends on a constant (case(3) ) whereas an if depends on an expression (if(something_very_complicated == 3) then ) so there are possible optimizations available to the compiler for the case (which under the hood is like a computed go to).

Regards,

Mike Metcalf

James Van Buskirk

unread,
Jun 22, 2016, 5:56:31 PM6/22/16
to


"Alessandro" wrote in message
news:3c16af91-19de-4d07...@googlegroups.com...


> From a point of view of computational efficiency is there any
> significant different using an IF/ELSEIF... structure rather that a
> SELECT CASE one...?

SELECT CASE, in the simplest usages, can map directly to a jump
table. If you think a jump table is an appropriate branching
structure, try using it and see if the compiler produces one.


herrman...@gmail.com

unread,
Jun 23, 2016, 1:34:49 AM6/23/16
to
Computed GOTO traditionally, and SELECT/CASE more recently are expected
to compile to a branch table if the cases are densely numbered. That is, a range of
numbers without gaps, or with small gaps.

Some compilers might also do that with IF/ELSEIF, though that is less likely.

But now it depends on the flow structure. The indexed branch used with branch
tables pretty much disables any branch optimization, such as prediction.

If branch prediction does work, such as if some branches are much more common,
it is possible that IF/ELSEIF is faster.

In the Fortran 66 days, it was suggested that arithmetic IF is faster than a
computed GOTO with 2 or 3 choices. That is, actually stated by compiler
vendors.

-- glen

Damian Rouson

unread,
Jun 25, 2016, 1:48:34 AM6/25/16
to
On Wednesday, June 22, 2016 at 7:47:58 AM 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...?

I believe scientific programmers have a strong tendency to overly weight performance relative to clarity when comparing alternative coding strategies. Your question doesn't indicate which of these two criteria is of interest. The answers so far relate primarily to whether there is any difference in terms of optimization, which is a performance issue. As my co-author Jim Xia once said to me on a performance question, "Let the compiler do its job."

If both statements are applicable, then SELECT CASE is more clear because it applies in only a subset of the cases for which IF/ELSEIF applies. Choosing SELECT CASE immediate communicates to the reader that the logic fits the pattern of that subset. In particular, SELECT CASE applies when the condition around which the logic revolves is a test of the value of one variable, expression, or function result. Each condition then corresponds to a different value for the relevant variable, expression, or function result; whereas IF/ELSEIF is much more general and the reader might need to traverse every branch before he or she can sort out the overall schema. I would start with an assumption that the communicative value of choosing SELECT CASE is more important than the performance unless have an execution profile that identifies the relevant block of code as the bottleneck in the application of interest. And if it turns out that IF/ELSEIF performs better, then I would document the choice in a comment and report the performance results to the compiler team.

Damian

Dieter Britz

unread,
Jun 25, 2016, 4:36:12 AM6/25/16
to
Do you mean to say that this resulted in significant reduction
in computing time? As weighed against clarity of programming?

--
Dieter Britz

Dieter Britz

unread,
Jun 25, 2016, 4:39:18 AM6/25/16
to
On Fri, 24 Jun 2016 22:48:31 -0700, Damian Rouson wrote:

> On Wednesday, June 22, 2016 at 7:47:58 AM 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...?
>
> I believe scientific programmers have a strong tendency to overly weight
> performance relative to clarity when comparing alternative coding
> strategies. Your question doesn't indicate which of these two criteria

I am one, and I prefer clarity, so that I will know what I did, 6 months
later. I don't care whether a program runs 60 sec or 50.

--
Dieter Britz

Gordon Sande

unread,
Jun 25, 2016, 11:17:59 AM6/25/16
to
On 2016-06-25 05:48:31 +0000, Damian Rouson said:

> On Wednesday, June 22, 2016 at 7:47:58 AM 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...?
>
> I believe scientific programmers have a strong tendency to overly
> weight performance relative to clarity when comparing alternative
> coding strategies. Your question doesn't indicate which of these two
> criteria is of interest. The answers so far relate primarily to whether
> there is any difference in terms of optimization, which is a
> performance issue. As my co-author Jim Xia once said to me on a
> performance question, "Let the compiler do its job."


There is a claimed Knuth quote that goes "Premature optimization is the
root of all evil".
It is likely that someone else said something close.

The great attention to efficiency dates from the "good old days" when
machines filled
a whole room, cost $1000 per hour and had speed measured in MHz (thats
M for mega) and
"no one would ever need more that 640K memory". IBM/7090s had 128k
organized as 32k
words. My several year old desktop has 12 threads running at 3+GHz with
6GB memory
so times have changed. The work per clock tick is down a bit so the
speedups as not
quite that large but still huge. And a $ was still worth a $ back then.

Having been a user of line by line execution profiles I can report that
in excess of 90%
of the source is responsible for less than 10% of the execution time.
And I also note
that that 90% seems to include the code that consumes much more than
10% of the debugging
effort. By line by line profiles I do not mean the location counter
samplers that claim
to be profilers but rather the source instumenters that get it exact.
In short, algorithms
matter and micro optimizations are a waste of effort. To much obscure
micro optimization
will make it much harder to improve the algorithms once you have
debugged all those micro
optimizations.

Gary Scott

unread,
Jun 25, 2016, 12:30:02 PM6/25/16
to
On 6/25/2016 12:48 AM, Damian Rouson wrote:
> On Wednesday, June 22, 2016 at 7:47:58 AM 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...?
>
> I believe scientific programmers have a strong tendency to overly weight performance relative to clarity when comparing alternative coding strategies. Your question doesn't indicate which of these two criteria is of interest. The answers so far relate primarily to whether there is any difference in terms of optimization, which is a performance issue. As my co-author Jim Xia once said to me on a performance question, "Let the compiler do its job."

I generally focus on performance only specifically where it matters. If
I'm controlling or monitoring external IO devices, I need a good
understanding of the timing. I may not need it to be as fast as
possible, but I need to have the timing issues understood and controlled
as much as possible. If I have to isolate a section of code to its own
process and elevate it to real time priority, I limit it to as little
work as possible at that priority level.

herrman...@gmail.com

unread,
Jun 25, 2016, 3:26:28 PM6/25/16
to
On Saturday, June 25, 2016 at 8:17:59 AM UTC-7, Gordon Sande wrote:
> On 2016-06-25 05:48:31 +0000, Damian Rouson said:

(snip on efficiency of IF/ELSE vs SELECT/CASE)

> > I believe scientific programmers have a strong tendency to overly
> > weight performance relative to clarity when comparing alternative
> > coding strategies.

Well that is true, but some of those times it is important. In the inner loop
where it gets executed billions or trillions of times, nanoseconds can turn
into hours, or even days.

> > Your question doesn't indicate which of these two
> > criteria is of interest. The answers so far relate primarily to whether
> > there is any difference in terms of optimization, which is a
> > performance issue. As my co-author Jim Xia once said to me on a
> > performance question, "Let the compiler do its job."

> There is a claimed Knuth quote that goes "Premature optimization is the
> root of all evil".
> It is likely that someone else said something close.

Sometimes there is the fun of solving a puzzle, needed or not.

But yes, many optimizations are done that aren't needed, and more time
is spent doing them, and discussing them, than saved.


> The great attention to efficiency dates from the "good old days" when
> machines filled a whole room, cost $1000 per hour and had speed
> measured in MHz (thats M for mega) and "no one would ever need
> more that 640K memory". IBM/7090s had 128k organized as 32k
> words.

Again true, but as computers get faster, problems that previously couldn't
be done now can be, and need to be. And many of those take a long time
on even the fastest current computer.

Even knowing that, I find it interesting how much work has been done in
recent years, maybe the last 10 or 15, to speed up function calls.

> My several year old desktop has 12 threads running at 3+GHz with
> 6GB memory so times have changed. The work per clock tick is down
> a bit so the speedups as not quite that large but still huge.
> And a $ was still worth a $ back then.

Also, you have to watch how an algorithm scales.

Often, a program will work fine for small data sets, and not well at all for
larger ones. Sometimes it is obvious, but not always.

Some years ago, I was working on a program that read in DNA sequence
data line by line, and appended it to make a large character array in
memory. It turns out that doing that is O(N**2), but for small problems
that is fine. When the sequences get to millions of characters long, it is
very slow. O(N**2) sort algorithms are well known, and most of us know
where not to use them, but reading in data isn't normally the O(N**2) part
of an algorithm!

As for readability, some find IF/ELSE more readable. If properly indented,
such that it is easy to see that all are comparing the same variable, IF/ELSE
is probably fine.

-- glen

herrman...@gmail.com

unread,
Jun 25, 2016, 3:34:14 PM6/25/16
to
On Friday, June 24, 2016 at 10:48:34 PM UTC-7, Damian Rouson wrote:

(snip)

> If both statements are applicable, then SELECT CASE is more clear because it
> applies in only a subset of the cases for which IF/ELSEIF applies.

(snip)

> And if it turns out that IF/ELSEIF performs better, then I would document the
> choice in a comment and report the performance results to the compiler team.

Not so obvious. The difference can be data dependent. Assuming the processor
has branch prediction, and for some data patterns, IF/ELSE could be a lot
faster, but the compiler doesn't know at all about the data pattern that the
user might have, and the programmer might also not know.

But okay, anyone interested in bringing back the FREQUENCY statement
from Fortran I?

FREQUENCY was used to help the compiler, giving the relative frequencies
of branch choices for arithmetic IF and computed GOTO, and also estimates
for the number of iterations for DO loops. Completely optional, it allows one
to supply the compiler with data pattern information that the programmer might
know, and the compiler won't be able to guess.

Seems to me that it could also work for SELECT/CASE, and might help in
some cases.

-- glen

Terence

unread,
Jun 25, 2016, 8:20:46 PM6/25/16
to
Glen asked :-
"But okay, anyone interested in bringing back the FREQUENCY statement
from Fortran I? "

I answer "NO" to the question as stated, but I prefer the intention of using
probability to save time.

I was taught Fortran I, but really only used II and 4/1/61 (unissued III),
to get experience, and then later IV on the big machines, when in IBM. I
don't recall ever seeing a FREQUENCY statement though. Of course I still use
F77.

If speed of solution would be important, in a program that would be used
more than once (or urgency was an issue), I tested for the condition that
eliminated the larger part of two subsets, where the larger part was
thought, or known, to be the most unlikely. Then I continued coding along
the same lines, to break up the smaller subset again based on expected
probabilities, to reach a point where it was worthwhile using the ASSIGNED
GOTO to specialised further tests.

Binary splitting always has been attractive to me; and in theory is the most
efficient, but not in real life.
e.g., money and energy and digits in human counts tend to follow
logarithmic probability






robin....@gmail.com

unread,
Jun 26, 2016, 7:10:34 PM6/26/16
to
In which case SELECT should have produced equally efficient results,
and which is preferable.

Stefano Zaghi

unread,
Jun 27, 2016, 12:26:23 AM6/27/16
to
Dear all,

I would like to have your opinions on the following question. A premise: I follow the Damian's teachings, thus often I prefer conciseness and clearness over obscure optimization. Some years ago I switched a critical algorithm branch from "if-elseif" to "select case", just because the "mapping" on the 6 zones was more clear than inequalities comparison, see this:

https://github.com/szaghi/OFF/blob/master/src/Lib_Riemann.f90#L554

This branching must be done trilions of times in production, so performance was not irrelevant, but after some tests it emerged that the difference was negligible. This result was in contrast with what I often read.

I always wondering why "if" should be more likely "optimizable" than "select case": I view "select case" a less general (due to constant-valued selectors) "brancher" than "if" (I cannot do with "select case" all that I can do with "if), thus my first guess was that the compiler's optimizer can be more easily optimize a select case than an if construct, but I often read the contrary.

Can you explain why?

My best regards.

herrman...@gmail.com

unread,
Jun 27, 2016, 2:15:42 AM6/27/16
to
If the compiler generates conditional branches, then it should be about the same
either way. You get whatever optimization the hardware branch prediction logic
can give you, which depends on how predictable the branches are.

If it generates a branch table and indexed branch, then, on processor I know of, there
is no branch prediction.

If the same CASE is used for most iterations of the loop, such as an algorithm selector
based on user input that doesn't change during a run, prediction should help and
IF/ELSEIF would likely work better. See:

https://en.wikipedia.org/wiki/Branch_predictor#Saturating_counter

for example.

Stefano Zaghi

unread,
Jun 27, 2016, 3:20:48 AM6/27/16
to
Il giorno lunedì 27 giugno 2016 08:15:42 UTC+2, herrman...@gmail.com ha scritto:
> If the same CASE is used for most iterations of the loop, such as an algorithm selector
> based on user input that doesn't change during a run, prediction should help and
> IF/ELSEIF would likely work better. See:
>
> https://en.wikipedia.org/wiki/Branch_predictor#Saturating_counter
>
> for example.

Dear Herrman, thank you for your help. Indeed, I was thinking more to a case where the conditions to be tested really change at runtime. In the example I posted previously the (inter)state (of a fluid) changes in-between the 6 states with an "unpredictable" pattern, that is not the same a selecting an algorithm from user'input that does not change more at runtime. Currently, I am trimming out such a branching algorithm in flavor of a sort of Strategy Pattern.

My (surely erroneous) assumption in flavor of "select case" was based on the fact that for the select case we have at most one expression to be evaluated and the selectors are constant-valued, whereas for the "if-elseif" branching each "if" could have its own expression, so I was thinking that the compiler needs less effort to optimize the select case. Is this completely wrong? Can anyone report cases where it is "best practice" to avoid "select case"?

My best regards.

herrman...@gmail.com

unread,
Jun 27, 2016, 3:30:16 AM6/27/16
to
On Monday, June 27, 2016 at 12:20:48 AM UTC-7, Stefano Zaghi wrote:

(snip, I wrote)

> > https://en.wikipedia.org/wiki/Branch_predictor#Saturating_counter

> > for example.

> Dear Herrman, thank you for your help. Indeed, I was thinking more to a case
> where the conditions to be tested really change at runtime. In the example
> I posted previously the (inter)state (of a fluid) changes in-between the 6 states
> with an "unpredictable" pattern, that is not the same a selecting an algorithm
> from user'input that does not change more at runtime. Currently, I am trimming
> out such a branching algorithm in flavor of a sort of Strategy Pattern.

Yes, so the prediction will be equally poor in the two cases.

It used to be that they didn't predict at all for indexed branch, but it seems
that newer processors predict the same target as previously.

> My (surely erroneous) assumption in flavor of "select case" was based on
> the fact that for the select case we have at most one expression to be
> evaluated and the selectors are constant-valued, whereas for the "if-elseif"
> branching each "if" could have its own expression, so I was thinking
> that the compiler needs less effort to optimize the select case.
> Is this completely wrong? Can anyone report cases where it
> is "best practice" to avoid "select case"?

In most cases, it isn't the compiler but the actual hardware.

(There have been machines with static prediction, where the compiler
suggests that the branch is more or less likely to be taken.)

For a large fraction of branches in most programs, prediction works well.

For cases that can't be predicted, you take the penalty.

Stefano Zaghi

unread,
Jun 27, 2016, 3:59:54 AM6/27/16
to
Il giorno lunedì 27 giugno 2016 09:30:16 UTC+2, herrman...@gmail.com ha scritto:
> Yes, so the prediction will be equally poor in the two cases.

Dear Herrman, thank you for this clear statement.

> It used to be that they didn't predict at all for indexed branch, but it seems
> that newer processors predict the same target as previously.

Oh, so they simply assume that the previous target is the most probable next one.

> In most cases, it isn't the compiler but the actual hardware.

You are right, and my ignorance of the actual hardware is the source of my confusion.

> (There have been machines with static prediction, where the compiler
> suggests that the branch is more or less likely to be taken.)

Yes, I was thinking to this approach, and this is why I was erroneously thinking that "select case" is more "optimizable" than "if"... I was erroneously making the link between "static prediction" and "constant-valued selectors"...

> For cases that can't be predicted, you take the penalty.

I think that was my situation at that time: both "if" and "select case" were unpredictable, so the change in flavor to "select case" did not add any further penalties.

Thank you again,

my best regards.

Gordon Sande

unread,
Jun 27, 2016, 10:27:27 AM6/27/16
to
On 2016-06-27 07:20:45 +0000, Stefano Zaghi said:

> Il giorno lunedě 27 giugno 2016 08:15:42 UTC+2, herrman...@gmail.com ha
You may be seeing common subexpression optimization if the various IFs
only vary by
comparison to constants as the ability to express things as a SELECT
would suggest.

> My best regards.


William Clodius

unread,
Jun 27, 2016, 1:51:17 PM6/27/16
to
FREQUENCY was removed in Fortran II as many users misunderstood the
description and inserted the wrong values, and the compiler writers
actually coded the use of the option wrong. Users in practice even with
a clear understanding of the use of the option, had a poor ability to
predict the relative probbilities. I strongly suspect it would be even
more confusing for SELECT CASE. It is not clear to me how useful it is
with current processors, with branch predications, and speculative
execution.

paul.rich...@gmail.com

unread,
Jun 27, 2016, 3:41:42 PM6/27/16
to
On Wednesday, 22 June 2016 16:47:58 UTC+2, 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...?

It might be instructive to see how gfortran translates:

character(4) :: c
integer :: i
c= "abcd"
select case (c)
case ("abcd")
i = 1
case ("efgh")
i = 2
end select

if (c .eq. "abcd") then
i = 1
elseif (c .eq. "efgh") then
i = 2
end if
end

Using option -fdump-tree-original, the output is:

MAIN__ ()
{
character(kind=1) c[1:4];
integer(kind=4) i;

__builtin_memmove ((void *) &c, (void *) &"abcd"[1]{lb: 1 sz: 1}, 4);
{
integer(kind=4) case_num.1;
static struct _jump_struct_char1 jumptable.0[2] = {{.string1=&"abcd"[1]{lb: 1 sz: 1}, .string1_len=4, .string2=&"abcd"[1]{lb: 1 sz: 1}, .string2_len=4, .target=0}, {.string1=&"efgh"[1]{lb: 1 sz: 1}, .string1_len=4, .string2=&"efgh"[1]{lb: 1 sz: 1}, .string2_len=4, .target=1}};

case_num.1 = _gfortran_select_string ((void *) &jumptable.0, 2, &c, 4);
switch (case_num.1)
{
case 0:;
i = 1;
goto L.2;
case 1:;
i = 2;
goto L.2;
}
L.2:;
}
L.1:;
if (__builtin_memcmp ((void *) &c, (void *) &"abcd"[1]{lb: 1 sz: 1}, 4) == 0)
{
i = 1;
}
else
{
if (__builtin_memcmp ((void *) &c, (void *) &"efgh"[1]{lb: 1 sz: 1}, 4) == 0)
{
i = 2;
}
}
L.5:;
}

I am rather sure that other brands do something similar.

Paul

Tran Quoc Viet

unread,
Dec 3, 2017, 3:02:19 AM12/3/17
to
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...?

Yes. There is a significant difference on performance when using SELECT CASE instead of IF-THEN. Actually, your code using SELECT-CASE may run much SLOWER than using IF-THEN.

Last time we modified the well-known package FFTPACK5 by replacing the computed-GOTO by the SELECT-CASE. Compiling the package by the ifort (Intel compiler) or by the gfortran, the performances also took longer time. That's so wird!

This is my test (test.f90) showing that SELECT-CASE should not be used as high performance is required.

!
!
! This test shows a proof that inside a huge loop using IF-THEN
! to switch among cases is much more efficient than SELECT-CASE.
! It also proves that the 'obsolete' computed GOTO is faster
! than the SELECT-CASE in the circumstance. However, the IF-THEN
! is fastest.
!
!
program tt_goto_01
implicit none
double precision x1, x2, ss, st1, st2, st3, st4, st5
real t1, t2, dt1, dt2, dt3, dt4, dt5
integer i, j, N, key, narg
character(len=15) charg
!
! USAGE:
!
! Compiling:
! ifort -O3 test.f90
! or
! gfortran -O3 test.f90
!
! Executing:
! ./a.out 100 200 300
! or
! ./a.out 100 200 300 1000
!
! wherein the loop size N will be read as 100, 200, 300, and 1000
! serially.
!
st1 = 0.0d0
st2 = 0.0d0
st3 = 0.0d0
st4 = 0.0d0

narg = command_argument_count()
write(*,*) 'Number of input arguments: ', narg
!
!
!
DO 999 j = 1,Narg

charg = ''
call get_command_argument( j, charg )
read(charg,*) N

if ( N < 1 ) stop
!
!
! 1) Testing Computed GOTO:
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0

call cpu_time (t1)

do i = 1,N

key = mod(n,10) + 1

goto (12,22,13,23,14,24,15,25,16,26), key

12 ss = ss + dble(12)*x1*dble((-1)**key)
goto 100
22 ss = ss + dble(22)*x2*dble((-1)**key)
goto 100
13 ss = ss + dble(13)*x1*dble((-1)**key)
goto 100
23 ss = ss + dble(23)*x2*dble((-1)**key)
goto 100
14 ss = ss + dble(14)*x1*dble((-1)**key)
goto 100
24 ss = ss + dble(24)*x2*dble((-1)**key)
goto 100
15 ss = ss + dble(15)*x1*dble((-1)**key)
goto 100
25 ss = ss + dble(25)*x2*dble((-1)**key)
goto 100
16 ss = ss + dble(16)*x1*dble((-1)**key)
goto 100
26 ss = ss + dble(26)*x2*dble((-1)**key)

100 continue

enddo

call cpu_time (t2)

dt1 = t2 - t1
st1 = st1 + dt1

write(*,1) 'GOTO:', n, ss, dt1
!
!
! 2) Testing SELECT CASE:
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0

call cpu_time (t1)

do i = 1,N

key = mod(n,10) + 1

select case (key)
case (1)
ss = ss + dble(12)*x1*dble((-1)**key)
case (2)
ss = ss + dble(22)*x2*dble((-1)**key)
case (3)
ss = ss + dble(13)*x1*dble((-1)**key)
case (4)
ss = ss + dble(23)*x2*dble((-1)**key)
case (5)
ss = ss + dble(14)*x1*dble((-1)**key)
case (6)
ss = ss + dble(24)*x2*dble((-1)**key)
case (7)
ss = ss + dble(15)*x1*dble((-1)**key)
case (8)
ss = ss + dble(25)*x2*dble((-1)**key)
case (9)
ss = ss + dble(16)*x1*dble((-1)**key)
case (10)
ss = ss + dble(26)*x2*dble((-1)**key)
end select

enddo

call cpu_time (t2)

dt2 = t2 - t1
st2 = st2 + dt2

write(*,1) 'SELECT CASE:', n, ss, dt2
!
!
! 3) Testing IF-Goto:
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0

call cpu_time (t1)

do i = 1,N

key = mod(n,10) + 1

if ( key .eq. 1 ) goto 120
if ( key .eq. 2 ) goto 220
if ( key .eq. 3 ) goto 130
if ( key .eq. 4 ) goto 230
if ( key .eq. 5 ) goto 140
if ( key .eq. 6 ) goto 240
if ( key .eq. 7 ) goto 150
if ( key .eq. 8 ) goto 250
if ( key .eq. 9 ) goto 160
if ( key .eq. 10) goto 260

120 ss = ss + dble(12)*x1*dble((-1)**key)
goto 200
220 ss = ss + dble(22)*x2*dble((-1)**key)
goto 200
130 ss = ss + dble(13)*x1*dble((-1)**key)
goto 200
230 ss = ss + dble(23)*x2*dble((-1)**key)
goto 200
140 ss = ss + dble(14)*x1*dble((-1)**key)
goto 200
240 ss = ss + dble(24)*x2*dble((-1)**key)
goto 200
150 ss = ss + dble(15)*x1*dble((-1)**key)
goto 200
250 ss = ss + dble(25)*x2*dble((-1)**key)
goto 200
160 ss = ss + dble(16)*x1*dble((-1)**key)
goto 200
260 ss = ss + dble(26)*x2*dble((-1)**key)

200 continue

enddo

call cpu_time (t2)

dt3 = t2 - t1
st3 = st3 + dt3

write(*,1) 'IF-Goto:', n, ss, dt3
!
!
! 4) Testing IF-noGoto:
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0

call cpu_time (t1)

do i = 1,N

key = mod(n,10) + 1

if ( key .eq. 1 ) then
ss = ss + dble(12)*x1*dble((-1)**key)
goto 300
endif

if ( key .eq. 2 ) then
ss = ss + dble(22)*x2*dble((-1)**key)
goto 300
endif

if ( key .eq. 3 ) then
ss = ss + dble(13)*x1*dble((-1)**key)
goto 300
endif

if ( key .eq. 4 ) then
ss = ss + dble(23)*x2*dble((-1)**key)
goto 300
endif

if ( key .eq. 5 ) then
ss = ss + dble(14)*x1*dble((-1)**key)
goto 300
endif

if ( key .eq. 6 ) then
ss = ss + dble(24)*x2*dble((-1)**key)
goto 300
endif

if ( key .eq. 7 ) then
ss = ss + dble(15)*x1*dble((-1)**key)
goto 300
endif

if ( key .eq. 8 ) then
ss = ss + dble(25)*x2*dble((-1)**key)
goto 300
endif

if ( key .eq. 9 ) then
ss = ss + dble(16)*x1*dble((-1)**key)
goto 300
endif

if ( key .eq. 10) then
ss = ss + dble(26)*x2*dble((-1)**key)
goto 300
endif
!
300 continue

enddo

call cpu_time (t2)

dt4 = t2 - t1
st4 = st4 + dt4

write(*,1) 'IF-noGoto:', n, ss, dt4
!
!
! 5) Testing IF-ELSE:
!
ss = 0.0d0
x1 = 1.234d0
x2 = 4.321d0

call cpu_time (t1)

do i = 1,N

key = mod(n,10) + 1

if ( key .eq. 1 ) then
ss = ss + dble(12)*x1*dble((-1)**key)
else if ( key .eq. 2 ) then
ss = ss + dble(22)*x2*dble((-1)**key)
else if ( key .eq. 3 ) then
ss = ss + dble(13)*x1*dble((-1)**key)
else if ( key .eq. 4 ) then
ss = ss + dble(23)*x2*dble((-1)**key)
else if ( key .eq. 5 ) then
ss = ss + dble(14)*x1*dble((-1)**key)
else if ( key .eq. 6 ) then
ss = ss + dble(24)*x2*dble((-1)**key)
else if ( key .eq. 7 ) then
ss = ss + dble(15)*x1*dble((-1)**key)
else if ( key .eq. 8 ) then
ss = ss + dble(25)*x2*dble((-1)**key)
else if ( key .eq. 9 ) then
ss = ss + dble(16)*x1*dble((-1)**key)
else if ( key .eq. 10) then
ss = ss + dble(26)*x2*dble((-1)**key)
endif
!
enddo

call cpu_time (t2)

dt5 = t2 - t1
st5 = st5 + dt5

write(*,1) 'IF-ELSE:', n, ss, dt5
!
!
write(*,*)
!
999 CONTINUE
!
! Finally reporting the result:
!
write(*,3) 'GOTO', st1
write(*,3) 'SELECT CASE', st2
write(*,3) 'IF-Goto', st3
write(*,3) 'IF-noGoto', st4
write(*,3) 'IF-ELSE', st5
write(*,4) 'Total time:', st1 + st2 + st3 + st4 + st5
!
! Format section:
!
1 format( a15, 1x, 'n =', i9, ', 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


Thomas Koenig

unread,
Dec 3, 2017, 5:02:40 AM12/3/17
to
Tran Quoc Viet <vie...@gmail.com> schrieb:
> Yes. There is a significant difference on performance when
> using SELECT CASE instead of IF-THEN. Actually, your code using
> SELECT-CASE may run much SLOWER than using IF-THEN.

I ran your test case with current trunk. I had to adjust the
number of runs upward to see anything, but I can confirm that
select case is slower.

This is now https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83262
.

michael...@compuserve.com

unread,
Dec 3, 2017, 6:15:27 AM12/3/17
to
On Sunday, 3 December 2017 09:02:19 UTC+1, Tran Quoc Viet wrote:
> 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...?
>
> Yes. There is a significant difference on performance when using SELECT CASE instead of IF-THEN. Actually, your code using SELECT-CASE may run much SLOWER than using IF-THEN.
>
> Last time we modified the well-known package FFTPACK5 by replacing the computed-GOTO by the SELECT-CASE. Compiling the package by the ifort (Intel compiler) or by the gfortran, the performances also took longer time. That's so wird!
>
> This is my test (test.f90) showing that SELECT-CASE should not be used as high performance is required.
>

You don't tell us your timings. When I ran your code with the Intel compiler, I had to set N to 1000000000 before I got any sensible time lapse, the output then being

GOTO: n =*********, ss =-0.1480800E+11, time = 1.188 (s)*********
SELECT CASE: n =*********, ss =-0.1480800E+11, time = 1.172 (s)*********
IF-Goto: n =*********, ss =-0.1480800E+11, time = 1.188 (s)*********
IF-noGoto: n =*********, ss =-0.1480800E+11, time = 1.203 (s)*********
IF-ELSE: n =*********, ss =-0.1480800E+11, time = 1.156 (s)*********

GOTO costs totally 1.188 (s)
SELECT CASE costs totally 1.172 (s)
IF-Goto costs totally 1.188 (s)
IF-noGoto costs totally 1.203 (s)
IF-ELSE costs totally 1.156 (s)
Total time: 5.906 (s)

Hardly a dramatic difference! My conclusion would be that it doesn't matter.

Regards,

Mike Metcalf

dpb

unread,
Dec 3, 2017, 9:22:59 AM12/3/17
to
On 03-Dec-17 5:15 AM, michael...@compuserve.com wrote:
...

> You don't tell us your timings. When I ran your code with the Intel
> compiler, I had to set N to 1000000000 before I got any sensible time
> lapse, the output then being
>
> GOTO: n =*********, ss =-0.1480800E+11, time = 1.188 (s)*********
> SELECT CASE: n =*********, ss =-0.1480800E+11, time = 1.172 (s)*********
> IF-Goto: n =*********, ss =-0.1480800E+11, time = 1.188 (s)*********
> IF-noGoto: n =*********, ss =-0.1480800E+11, time = 1.203 (s)*********
> IF-ELSE: n =*********, ss =-0.1480800E+11, time = 1.156 (s)*********
>
> GOTO costs totally 1.188 (s)
> SELECT CASE costs totally 1.172 (s)
> IF-Goto costs totally 1.188 (s)
> IF-noGoto costs totally 1.203 (s)
> IF-ELSE costs totally 1.156 (s)
> Total time: 5.906 (s)
>
> Hardly a dramatic difference! My conclusion would be that it doesn't matter.
...

Pretty much, altho if on looks into the weeds, it turns out that

IF-ELSE costs totally 1.156 (s)
SELECT CASE costs totally 1.172 (s)

are the two best, SELECT CASE actually being better than 3 out of the 5
(for the particular compiler/processor/OS/release of each, of course).

GOTO is actually in a tie for third best...

--

Dick Hendrickson

unread,
Dec 3, 2017, 11:38:42 AM12/3/17
to
Does this do what you think it does? "n" never changes in the inner
loop. Wouldn't it make more sense to use "i" in the mod? With key
unchanging won't branch prediction distort the results? Or have I
missed something?

Dick Hendrickson

herrman...@gmail.com

unread,
Dec 3, 2017, 2:53:45 PM12/3/17
to
On Sunday, December 3, 2017 at 6:22:59 AM UTC-8, dpb wrote:
> On 03-Dec-17 5:15 AM, michaelmet....@compuserve.com wrote:


(snip comparing IF/ELSE with SELECT/CASE)

> > Hardly a dramatic difference!
> > My conclusion would be that it doesn't matter.

> Pretty much, altho if on looks into the weeds, it turns out that

> IF-ELSE costs totally 1.156 (s)
> SELECT CASE costs totally 1.172 (s)

> are the two best, SELECT CASE actually being better than 3 out of the 5
> (for the particular compiler/processor/OS/release of each, of course).

> GOTO is actually in a tie for third best...

It is very hard to do good comparisons for this.

For one, compiler optimization can make it very sensitive to
the actual way it is written, which might not generalize.

Second, branch prediction in the processor makes it sensitive
to the pattern of the selection values. One test case could
be very different from the actual case, and get different
results.

But also note the old warning about premature optimization.

Unless you know that a significant time is being spent for
this operation, and the time spent optimizing the actual use
(not benchmarks that look similar), it is better not to try.

My prediction is that SELECT/CASE will be faster when the
choices are somewhat random, and IF/ELSE when they are less
random.







dpb

unread,
Dec 3, 2017, 3:11:23 PM12/3/17
to
On 03-Dec-17 1:53 PM, herrman...@gmail.com wrote:
> On Sunday, December 3, 2017 at 6:22:59 AM UTC-8, dpb wrote:
>> On 03-Dec-17 5:15 AM, michaelmet....@compuserve.com wrote:
>
>
> (snip comparing IF/ELSE with SELECT/CASE)
>
>>> Hardly a dramatic difference!
>>> My conclusion would be that it doesn't matter.
>
>> Pretty much, altho if on looks into the weeds, it turns out that
>
>> IF-ELSE costs totally 1.156 (s)
>> SELECT CASE costs totally 1.172 (s)
>
>> are the two best, SELECT CASE actually being better than 3 out of the 5
>> (for the particular compiler/processor/OS/release of each, of course).
>
>> GOTO is actually in a tie for third best...
>
> It is very hard to do good comparisons for this.
>
> For one, compiler optimization can make it very sensitive to
> the actual way it is written, which might not generalize.
...


Yes, I made particular note of this being only for the one specific test
case for the given implementation.

I only pointed it out as did because it seems to refute the OPs
implication that SELECT CASE would be/is _much_ worse when in fact for
the given test case there's probably a statistically insignificant
difference at all and that the SELECT CASE for the particular
instantiation is nearly the winner as opposed to the clear loser...

I would wholeheartedly agree that presuming to rewrite anything on this
basis would be a generally wasteful thing to do.

--

michael...@compuserve.com

unread,
Dec 3, 2017, 3:13:02 PM12/3/17
to
Making the eminently sensible change that Dick suggested, we get, with a factor 10 less for N:

GOTO: n =100000000, ss = 0.4321400E+10, time = 0.750 (s)
SELECT CASE: n =100000000, ss = 0.4321400E+10, time = 0.750 (s)
IF-Goto: n =100000000, ss = 0.4321400E+10, time = 0.812 (s)
IF-noGoto: n =100000000, ss = 0.4321400E+10, time = 0.828 (s)
IF-ELSE: n =100000000, ss = 0.4321400E+10, time = 0.734 (s)

GOTO costs totally 0.750 (s)
SELECT CASE costs totally 0.750 (s)
IF-Goto costs totally 0.812 (s)
IF-noGoto costs totally 0.828 (s)
IF-ELSE costs totally 0.734 (s)
Total time: 3.875 (s)
Message has been deleted

Tran Quoc Viet

unread,
Dec 4, 2017, 3:20:39 AM12/4/17
to
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
!--------------------------------------------------------------------

Tran Quoc Viet

unread,
Dec 4, 2017, 3:44:40 AM12/4/17
to
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...?

So far, as my conclusion, we should avoid using SELECT CASE when high performance is required. The computed GOTO F77 feature works efficiently with Intel compiler (true with or without -O3). But it turns to the worst with Gfortran (both with and without -O3).

Now I'm happy with using IF-THEN combined with GOTO to switch cases.

Any comment or suggestion?

Stefano Zaghi

unread,
Dec 4, 2017, 4:04:38 AM12/4/17
to
Reading some previous comments this sounds the old myth about goto... but I am very curious to test this sentence (moreover goto prevents parallelism thus suggesting to use it in an HPC scenario has not sense).

I have not the time to carefully review your posts, can you re-send the last test you are using now?

My best regards.

herrman...@gmail.com

unread,
Dec 4, 2017, 4:24:16 AM12/4/17
to
Try random numbers for key, instead of mod(i, 10).
That makes it harder for branch prediction.

Also, try a binary tree of if/then/else as an additional
comparison test.

Tran Quoc Viet

unread,
Dec 4, 2017, 4:29:24 AM12/4/17
to
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 Stefano,

I clean-up some details of my last post, in which I have 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).

with the command line:

./a.out 100000000 300000000 500000000 700000000 900000000

Here is the output (short form):

Case 1) ifort -O3 test_v02.f90

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)
----------------------------------------------------------------------

Case 2) ifort test_v02.f90

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)
----------------------------------------------------------------------

Case 3) gfortran -O3 test_v02.f90

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)
----------------------------------------------------------------------

Case 4) gfortran test_v02.f90

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)
----------------------------------------------------------------------


P/S: Labels have been 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

campbel...@gmail.com

unread,
Dec 4, 2017, 5:07:39 AM12/4/17
to
I think these results again show there is an insignificant difference between the alternative logic structures, so we should all continue with our preferred coding approach. Once the calculations become significant, the control structure should not matter.
However, I would recommend against using CPU_TIME as a timing measure. On systems I use, it is accurate to only 1/64 sec. SYSTEM_CLOCK is more precise and any alternative based on RDTSC is likely to give a better indication.

Tran Quoc Viet

unread,
Dec 4, 2017, 5:24:25 AM12/4/17
to
On Monday, December 4, 2017 at 5:07:39 PM UTC+7, campbel...@gmail.com wrote:
> I think these results again show there is an insignificant difference between the alternative logic structures, so we should all continue with our preferred coding approach. Once the calculations become significant, the control structure should not matter.
> However, I would recommend against using CPU_TIME as a timing measure. On systems I use, it is accurate to only 1/64 sec. SYSTEM_CLOCK is more precise and any alternative based on RDTSC is likely to give a better indication.

I tried with your suggestion on adopting the SYSTEM_CLOCK. The times elapsing are the same.

bartc

unread,
Dec 4, 2017, 7:09:07 AM12/4/17
to
(What does 'dble' do? Is dble(12) just the same as 12.0?)

All your loops look like pretty terrible ways of writing almost
identical code. For example, all 10 lines can be expressed like this:

ss = ss + T(key) * X(key) * K(key)

where T is (12,22,13,23, .... ) (with dble() applied to each if needed),
X is (x1,x2,x1,x2, ....) and K is ((-1)**1, (-1)**2, ....). Then you
don't need 'select case' etc at all.

Either way, the timings are likely to be dominated by the times needed
for the floating point multiply and add ops, and for ** if the compiler
can't optimise that out. Plus of course the mod operation which involves
a divide.

For testing, you can't really trust what a compiler might be doing;
perhaps in some places, it could unfairly be leaving out code of your
contrived test that it might not be able to do in a real scenario.

Perhaps better to test with no optimisation to more easily see any
actual differences.

But if you did have ten different sets of code to select between, then
'select case' is the most natural way to write that, as 'key' is only
tested once, not 10 times, and there are no gotos.

--
bartc

dpb

unread,
Dec 4, 2017, 9:18:15 AM12/4/17
to
On 04-Dec-17 12:45 AM, Tran Quoc Viet wrote:
...

> As far as I know, Fortran ignores capitalization. Hence, n is N.

That wasn't Dick's point...

> Furthermore, since I want to run the test with multi-values of N
...

key = int(mod(N,ten),kind=4) + 1, from key = mod(N,10) + 1

Is the problem/question -- the loop is over i so N still doesn't change
inside the loop; hence key is a constant.

...

--

Ron Shepard

unread,
Dec 4, 2017, 11:11:01 AM12/4/17
to
Yes, but that is the nature of contrived benchmark tests.

> For example, all 10 lines can be expressed like this:
>
>   ss = ss + T(key) * X(key) * K(key)
>
> where T is (12,22,13,23, .... ) (with dble() applied to each if needed),
> X is (x1,x2,x1,x2, ....) and K is ((-1)**1, (-1)**2, ....). Then you
> don't need 'select case' etc at all.
>
> Either way, the timings are likely to be dominated by the times needed
> for the floating point multiply and add ops, and for ** if the compiler
> can't optimise that out. Plus of course the mod operation which involves
> a divide.

I think it might be a good idea to just look at the assembler code that
is being produced to see what are the differences. Or with gfortran, you
could look at the intermediate level code. The thing I would look at is
how much the compiler is doing at compile time. In the above code
snippet for example, each expression can be evaluated at compile time,
leaving something like

ss = ss + TEMP_KEY

where TEMP_KEY is evaluated once at compile time for each of the values
of key and then stored in an array or in registers for subsequent lookup
at runtime. If this is correct, then the only floating point operation
that is done each iteration of the do loop would be the floating point add.

On the other hand, if those expressions are not evaluated at compile
time, then they would result in several expensive floating point
operations each do loop cycle. The differences of whether these
expressions are evaluated at compile time or at runtime would then swamp
any of the small differences in the costs of integer lookup branches,
which is the operation that is being compared.

As I said above, these difficulties are due to the nature of contrived
benchmark tests. If you look at the assembler code, you might see that
you are timing something that has little to do with the relative costs
of the different ways to branch.

Also, maybe someone has already mentioned this, but gfortran 4.9 is over
three years old. The latest release version is 7.2 from August 2017. The
gfortran timings might reflect a problem that is already solved.

$.02 -Ron Shepard

Ron Shepard

unread,
Dec 4, 2017, 11:27:29 AM12/4/17
to
I missed that when I replied before. That is even a more serious problem
because it is the branch that is being compared, yet the branch does not
occur if the compiler recognizes that key is a constant and optimizes it
away entirely.

$.02 -Ron Shepard

Tran Quoc Viet

unread,
Dec 4, 2017, 12:13:49 PM12/4/17
to
Thank you, Ron Shepard.

As you and bartc suggested, I removed all the floating point operations out of the loop and rerun the test. The SELECT-CASE is still less efficient than the others.

This line
key = mod(N,10) + 1
is a big bug that Dick pointed out. I have changed it already in the previous post. It must be like the following line from original idea:
key = mod(i,ten) + 1

Anyway, I'd like to emphasize that all my conclusion above is based on my computer and compiler that I have. It'd would be much better if one runs the test on his computer and make his own conclusion. Again, here is the test modified from your suggestion.

!-----------------------------------------------------------------
!
! This test shows performance of the SELECT-CASE compared with
! other IF's types. Try on your computer and decide what shows
! the best performance.
!
program tt_goto_00
implicit none
double precision x1, x2, x3, x4, x5, x6, x7, x8, x9, x0
double precision ss, st1, st2, st3, st4, st5
real dt2, dt1, dt3, dt4, dt5
integer t1, t2, clock_rate, clock_max
integer N, ten, i
integer j, key, narg
character(len=15) charg
!
! USAGE:
!
! Compiling:
! ifort -O3 me.f90
! or
! gfortran -O3 me.f90
!
! Executing:
! ./a.out 10000000 20000000 30000000
! or
! ./a.out 10000000 20000000 30000000 50000000
!
! wherein the loop size N will be read serially. We can input more.
! Make the list of N above to be longer to get a statistical test.
!
!
st1 = 0.0d0
st2 = 0.0d0
st3 = 0.0d0
st4 = 0.0d0
!
ten = 10
!
x1 = 1.234d0
x2 = 2.234d0
x3 = 3.234d0
x4 = 4.234d0
x5 = 5.234d0
x6 = 6.234d0
x7 = 7.234d0
x8 = 8.234d0
x9 = 9.234d0
x0 = 0.234d0
!
narg = command_argument_count()
write(*,'(a,i3,/)') 'Number of values of N: ', 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 SELECT CASE: named 'SELECT-CASE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,ten) + 1

select case (key)
case (1)
ss = ss + x1
case (2)
ss = ss + x2
case (3)
ss = ss + x3
case (4)
ss = ss + x4
case (5)
ss = ss + x5
case (6)
ss = ss + x6
case (7)
ss = ss + x7
case (8)
ss = ss + x8
case (9)
ss = ss + x9
case (10)
ss = ss + x0
end select

101 continue

enddo

call system_clock ( t2, clock_rate, clock_max )

dt1 = real(t2-t1,8) / real(clock_rate,8)

st1 = st1 + dt1

write(*,1) 'SELECT-CASE:', N, ss, dt1
!
!
! 2) Testing Computed GOTO: named 'F77-GOTO'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,ten) + 1

goto (12,22,13,23,14,24,15,25,16,26), key

12 ss = ss + x1
goto 100
22 ss = ss + x2
goto 100
13 ss = ss + x3
goto 100
23 ss = ss + x4
goto 100
14 ss = ss + x5
goto 100
24 ss = ss + x6
goto 100
15 ss = ss + x7
goto 100
25 ss = ss + x8
goto 100
16 ss = ss + x9
goto 100
26 ss = ss + x0

100 continue

enddo

call system_clock ( t2, clock_rate, clock_max )

dt2 = real(t2-t1,8) / real(clock_rate,8)

st2 = st2 + dt2

write(*,1) 'F77-GOTO:', N, ss, dt2
!
!
! 3) Testing IF with Goto: named 'IF-Goto1'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,ten) + 1

if ( key .eq. 1 ) goto 120
if ( key .eq. 2 ) goto 220
if ( key .eq. 3 ) goto 130
if ( key .eq. 4 ) goto 230
if ( key .eq. 5 ) goto 140
if ( key .eq. 6 ) goto 240
if ( key .eq. 7 ) goto 150
if ( key .eq. 8 ) goto 250
if ( key .eq. 9 ) goto 160
if ( key .eq. 10) goto 260

120 ss = ss + x1
goto 200
220 ss = ss + x2
goto 200
130 ss = ss + x3
goto 200
230 ss = ss + x4
goto 200
140 ss = ss + x5
goto 200
240 ss = ss + x6
goto 200
150 ss = ss + x7
goto 200
250 ss = ss + x8
goto 200
160 ss = ss + x9
goto 200
260 ss = ss + x0

200 continue

enddo

call system_clock ( t2, clock_rate, clock_max )

dt3 = real(t2-t1,8) / real(clock_rate,8)

st3 = st3 + dt3

write(*,1) 'IF-Goto1:', N, ss, dt3
!
!
! 4) Testing IF with less Goto's: named 'IF-Goto2'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,ten) + 1

if ( key .eq. 1 ) then
ss = ss + x1
goto 300
endif

if ( key .eq. 2 ) then
ss = ss + x2
goto 300
endif

if ( key .eq. 3 ) then
ss = ss + x3
goto 300
endif

if ( key .eq. 4 ) then
ss = ss + x4
goto 300
endif

if ( key .eq. 5 ) then
ss = ss + x5
goto 300
endif

if ( key .eq. 6 ) then
ss = ss + x6
goto 300
endif

if ( key .eq. 7 ) then
ss = ss + x7
goto 300
endif

if ( key .eq. 8 ) then
ss = ss + x8
goto 300
endif

if ( key .eq. 9 ) then
ss = ss + x9
goto 300
endif

if ( key .eq. 10) then
ss = ss + x0
goto 300
endif
!
300 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt4 = real(t2-t1,8) / real(clock_rate,8)

st4 = st4 + dt4

write(*,1) 'IF-Goto2:', N, ss, dt4
!
!
! 5) Testing IF/ELSE: named 'IF-ELSE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,ten) + 1

if ( key .eq. 1 ) then
ss = ss + x1
else if ( key .eq. 2 ) then
ss = ss + x2
else if ( key .eq. 3 ) then
ss = ss + x3
else if ( key .eq. 4 ) then
ss = ss + x4
else if ( key .eq. 5 ) then
ss = ss + x5
else if ( key .eq. 6 ) then
ss = ss + x6
else if ( key .eq. 7 ) then
ss = ss + x7
else if ( key .eq. 8 ) then
ss = ss + x8
else if ( key .eq. 9 ) then
ss = ss + x9
else if ( key .eq. 10) then
ss = ss + x0
endif
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt5 = real(t2-t1,8) / real(clock_rate,8)

st5 = st5 + dt5

write(*,1) 'IF-ELSE:', N, ss, dt5
!
!
write(*,*)
!
999 CONTINUE
!
! Finally reporting the result:
!
write(*,2) 'SELECT-CASE', st1
write(*,2) 'F77-GOTO', st2
write(*,2) 'IF-Goto1', st3
write(*,2) 'IF-Goto2', st4
write(*,2) 'IF-ELSE', st5
write(*,3) 'Total time:', st1 + st2 + st3 + st4 + st5
!
! Format section:
!
1 format( a15, 1x, 'N =', i12, ', ss =', e14.7, &
', time = ', f8.3, ' (s)')
2 format( a15, 1x, 'costs totally ',1x, f8.3, ' (s)')
3 format( a15, 1x, f8.3, ' (s)', /, 70('-') )
!
stop
end program
!-----------------------------------------------------------------

bartc

unread,
Dec 4, 2017, 2:29:39 PM12/4/17
to
On 04/12/2017 17:13, Tran Quoc Viet wrote:

> As you and bartc suggested, I removed all the floating point operations out of the loop and rerun the test. The SELECT-CASE is still less efficient than the others.

What results did you get? I got these:

SELECT-CASE: N = 100000000, ss= 0.4734000E+09,time = 0.390
F77-GOTO: N = 100000000, ss= 0.4734000E+09,time = 0.546
IF-Goto1: N = 100000000, ss= 0.4734000E+09,time = 0.437
IF-Goto2: N = 100000000, ss= 0.4734000E+09,time = 0.437
IF-ELSE: N = 100000000, ss= 0.4734000E+09,time = 0.421

Compiling with GFortran 5.1.0 on Windows 7, Intel 3.2GHz, using:

gfortran -O3 test.f

(Actually, this is the first Fortran code I've compiled for some 38
years. The language looks a little ... different.)

Anyway, the SELECT-CASE timings seem to be the best.

However, the loop still contains 'mod(i,10)' which involves an integer
divide. If I change all those to iand(i,7) [this will give slightly
different results and only use the first eight lots of code in each
loop], then the results are bunched more tightly, and also a little
variable, but a typical run is:

SELECT-CASE: N = 100000000, ss= 0.4734000E+09,time = 0.219
F77-GOTO: N = 100000000, ss= 0.4734000E+09,time = 0.249
IF-Goto1: N = 100000000, ss= 0.4734000E+09,time = 0.203
IF-Goto2: N = 100000000, ss= 0.4734000E+09,time = 0.219
IF-ELSE: N = 100000000, ss= 0.4734000E+09,time = 0.218

This is not what I expected: it was the divide that should have been a
constant overhead for all loops! (And why does ss have the same result
as using mod?)

Turning off the optimiser as I suggested:

(Original:)
SELECT-CASE: N = 100000000, ss= 0.4734000E+09,time = 0.609
F77-GOTO: N = 100000000, ss= 0.4734000E+09,time = 0.624
IF-Goto1: N = 100000000, ss= 0.4734000E+09,time = 0.764
IF-Goto2: N = 100000000, ss= 0.4734000E+09,time = 0.796
IF-ELSE: N = 100000000, ss= 0.4734000E+09,time = 0.780

(Using iand:)
SELECT-CASE: N = 100000000, ss= 0.4734000E+09,time = 0.374
F77-GOTO: N = 100000000, ss= 0.4734000E+09,time = 0.609
IF-Goto1: N = 100000000, ss= 0.4734000E+09,time = 0.483
IF-Goto2: N = 100000000, ss= 0.4734000E+09,time = 0.484
IF-ELSE: N = 100000000, ss= 0.4734000E+09,time = 0.499

It still seems to me that SELECT-CASE is the best choice both for
performance, and readability.


> 1 format( a15, 1x, 'N =', i12, ', ss =', e14.7, &
> ', time = ', f8.3, ' (s)')

Mysteriously, GFortran 5.1.0 didn't like this final ' (s)'. I had to
take it out.

--
bartc

robin....@gmail.com

unread,
Dec 4, 2017, 9:51:19 PM12/4/17
to
DBLE is a standard intrinsic, since FORTRAN days.
It produces a double-precision result,
and dble(12) is therefore equivalent to 12.0D0

Tran Quoc Viet

unread,
Dec 4, 2017, 11:19:37 PM12/4/17
to
Thank you, Bartc.

Your results are interesting.

And Yes. You're right. The floating point operations cost time mainly.

When I replace mod(i,10) by iand(i,7), time-elapsing is reduced much.

SELECT-CASE now turns to the fastest one with Ifort and Gfortran (4.9.2) with '-O3'.

So, just try and make your own conclusion.

Again, here is the new version:

!
!
! This test shows performance of the SELECT-CASE compared with
! other IF's types. Try on your computer and decide what shows
! the best performance.
!
! News: This test goes with less floating point operations
! by replacing
! key = mode(i,10) + 1
! by
! key = iand(i,7) + 1
! as suggested by Bartc, from comp.lang.fortran.
!
!
program tt_goto_01
implicit none
double precision x1, x2, x3, x4, x5, x6, x7, x8, x9, x0
double precision ss, st1, st2, st3, st4, st5
real dt2, dt1, dt3, dt4, dt5
integer t1, t2, clock_rate, clock_max
integer N, ten, i
integer j, key, narg
character(len=15) charg
!
! USAGE:
!
! Compiling:
! ifort -O3 tt_goto_00.f90
! or
! gfortran -O3 tt_goto_00.f90
!
! Executing:
! ./a.out 900000000
! or
! ./a.out 100000000 300000000 500000000 700000000 900000000
!
! wherein the loop size N will be read serially. We can input more.
! Make the list of N above to be longer to get a statistical test.
!
!
narg = command_argument_count()
!
if ( narg .lt. 1 ) then
write(*,'(a)') './a.out 10000000 30000000 50000000 70000000'
stop
endif
!
write(*,'(a,i3,/)') 'Number of values of N: ', narg
!
st1 = 0.0d0
st2 = 0.0d0
st3 = 0.0d0
st4 = 0.0d0
!
ten = 10
!
x1 = 1.234d0
x2 = 2.234d0
x3 = 3.234d0
x4 = 4.234d0
x5 = 5.234d0
x6 = 6.234d0
x7 = 7.234d0
x8 = 8.234d0
x9 = 9.234d0
x0 = 0.234d0
!
! 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 SELECT CASE: named 'SELECT-CASE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = iand(i,7) + 1

select case (key)
case (1)
ss = ss + x1
case (2)
ss = ss + x2
case (3)
ss = ss + x3
case (4)
ss = ss + x4
case (5)
ss = ss + x5
case (6)
ss = ss + x6
case (7)
ss = ss + x7
case (8)
ss = ss + x8
case (9)
ss = ss + x9
case (10)
ss = ss + x0
end select
!
101 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt1 = real(t2-t1,8) / real(clock_rate,8)

st1 = st1 + dt1

write(*,1) 'SELECT-CASE:', N, ss, dt1
!
!
! 2) Testing Computed GOTO: named 'F77-GOTO'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = iand(i,7) + 1

goto (12,22,13,23,14,24,15,25,16,26), key

goto 102

12 ss = ss + x1
goto 102
22 ss = ss + x2
goto 102
13 ss = ss + x3
goto 102
23 ss = ss + x4
goto 102
14 ss = ss + x5
goto 102
24 ss = ss + x6
goto 102
15 ss = ss + x7
goto 102
25 ss = ss + x8
goto 102
16 ss = ss + x9
goto 102
26 ss = ss + x0
!
102 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt2 = real(t2-t1,8) / real(clock_rate,8)

st2 = st2 + dt2

write(*,1) 'F77-GOTO:', N, ss, dt2
!
!
! 3) Testing IF with Goto: named 'IF-Goto1'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = iand(i,7) + 1

if ( key .eq. 1 ) goto 120
if ( key .eq. 2 ) goto 220
if ( key .eq. 3 ) goto 130
if ( key .eq. 4 ) goto 230
if ( key .eq. 5 ) goto 140
if ( key .eq. 6 ) goto 240
if ( key .eq. 7 ) goto 150
if ( key .eq. 8 ) goto 250
if ( key .eq. 9 ) goto 160
if ( key .eq. 10) goto 260

goto 103

120 ss = ss + x1
goto 103
220 ss = ss + x2
goto 103
130 ss = ss + x3
goto 103
230 ss = ss + x4
goto 103
140 ss = ss + x5
goto 103
240 ss = ss + x6
goto 103
150 ss = ss + x7
goto 103
250 ss = ss + x8
goto 103
160 ss = ss + x9
goto 103
260 ss = ss + x0
!
103 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt3 = real(t2-t1,8) / real(clock_rate,8)

st3 = st3 + dt3

write(*,1) 'IF-Goto1:', N, ss, dt3
!
!
! 4) Testing IF with less Goto's: named 'IF-Goto2'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = iand(i,7) + 1

if ( key .eq. 1 ) then
ss = ss + x1
goto 104
endif

if ( key .eq. 2 ) then
ss = ss + x2
goto 104
endif

if ( key .eq. 3 ) then
ss = ss + x3
goto 104
endif

if ( key .eq. 4 ) then
ss = ss + x4
goto 104
endif

if ( key .eq. 5 ) then
ss = ss + x5
goto 104
endif

if ( key .eq. 6 ) then
ss = ss + x6
goto 104
endif

if ( key .eq. 7 ) then
ss = ss + x7
goto 104
endif

if ( key .eq. 8 ) then
ss = ss + x8
goto 104
endif

if ( key .eq. 9 ) then
ss = ss + x9
goto 104
endif

if ( key .eq. 10) then
ss = ss + x0
goto 104
endif
!
104 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt4 = real(t2-t1,8) / real(clock_rate,8)

st4 = st4 + dt4

write(*,1) 'IF-Goto2:', N, ss, dt4
!
!
! 5) Testing IF/ELSE: named 'IF-ELSE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = iand(i,7) + 1

if ( key .eq. 1 ) then
ss = ss + x1
else if ( key .eq. 2 ) then
ss = ss + x2
else if ( key .eq. 3 ) then
ss = ss + x3
else if ( key .eq. 4 ) then
ss = ss + x4
else if ( key .eq. 5 ) then
ss = ss + x5
else if ( key .eq. 6 ) then
ss = ss + x6
else if ( key .eq. 7 ) then
ss = ss + x7
else if ( key .eq. 8 ) then
ss = ss + x8
else if ( key .eq. 9 ) then
ss = ss + x9
else if ( key .eq. 10) then
ss = ss + x0
endif
!
105 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt5 = real(t2-t1,8) / real(clock_rate,8)

st5 = st5 + dt5

write(*,1) 'IF-ELSE:', N, ss, dt5
!
!
write(*,*)
!
999 CONTINUE
!
! Finally reporting the result:
!
write(*,2) 'SELECT-CASE', st1
write(*,2) 'F77-GOTO', st2
write(*,2) 'IF-Goto1', st3
write(*,2) 'IF-Goto2', st4
write(*,2) 'IF-ELSE', st5
write(*,3) 'Total time:', st1 + st2 + st3 + st4 + st5
!
! Format section:
!
1 format( a15, 1x, 'N =', i12, ', ss =', e14.7, &
', time = ', f8.3, ' (s)')

herrman...@gmail.com

unread,
Dec 5, 2017, 12:08:22 AM12/5/17
to
On Monday, December 4, 2017 at 6:51:19 PM UTC-8, robin....@gmail.com wrote:
> On Monday, December 4, 2017 at 11:09:07 PM UTC+11, bartc wrote:

(snip)

> > (What does 'dble' do? Is dble(12) just the same as 12.0?)

> DBLE is a standard intrinsic, since FORTRAN days.
> It produces a double-precision result,
> and dble(12) is therefore equivalent to 12.0D0

Yes, but it is supposed to have a single precision argument,
at least in the Fortran 66 version.

Ev. Drikos

unread,
Dec 5, 2017, 12:50:42 AM12/5/17
to
On 05/12/2017 06:19, Tran Quoc Viet wrote:
> ...

The first test below has been compiled with the option -fno-align-jumps,
as mentioned in GNU Bugzilla.

The second test has an extra "case" in the "select case" statement:
case (0)
error stop;

Both test cases have been compiled with the much older (and much slower)
4.8 version and perhaps these tips are version specific. If both the
option '-fno-align-jumps' and the modification "case (0)" are omitted
the "select-case" is much slower.

Ev. Drikos

--------------------------------------------------------------------------
$ gfc -O3 -fno-align-jumps select_case_new.f90 -o select_case_new_nj
$ ./select_case_new_nj 100000000 200000000 300000000
Number of values of N: 3

SELECT-CASE: N = 100000000, ss = 0.4734000E+09, time = 0.230 (s)
F77-GOTO: N = 100000000, ss = 0.4734000E+09, time = 0.183 (s)
IF-Goto1: N = 100000000, ss = 0.4734000E+09, time = 0.209 (s)
IF-Goto2: N = 100000000, ss = 0.4734000E+09, time = 0.190 (s)
IF-ELSE: N = 100000000, ss = 0.4734000E+09, time = 0.194 (s)

SELECT-CASE: N = 200000000, ss = 0.9468000E+09, time = 0.426 (s)
F77-GOTO: N = 200000000, ss = 0.9468000E+09, time = 0.360 (s)
IF-Goto1: N = 200000000, ss = 0.9468000E+09, time = 0.410 (s)
IF-Goto2: N = 200000000, ss = 0.9468000E+09, time = 0.383 (s)
IF-ELSE: N = 200000000, ss = 0.9468000E+09, time = 0.389 (s)

SELECT-CASE: N = 300000000, ss = 0.1420200E+10, time = 0.645 (s)
F77-GOTO: N = 300000000, ss = 0.1420200E+10, time = 0.538 (s)
IF-Goto1: N = 300000000, ss = 0.1420200E+10, time = 0.611 (s)
IF-Goto2: N = 300000000, ss = 0.1420200E+10, time = 0.563 (s)
IF-ELSE: N = 300000000, ss = 0.1420200E+10, time = 0.582 (s)

SELECT-CASE costs totally 1.301 (s)
F77-GOTO costs totally 1.081 (s)
IF-Goto1 costs totally 1.230 (s)
IF-Goto2 costs totally 1.136 (s)
IF-ELSE costs totally 1.165 (s)
Total time: 5.913 (s)
----------------------------------------------------------------------
$ ./select_case_new 100000000 200000000 300000000
Number of values of N: 3

SELECT-CASE: N = 100000000, ss = 0.4734000E+09, time = 0.194 (s)
F77-GOTO: N = 100000000, ss = 0.4734000E+09, time = 0.214 (s)
IF-Goto1: N = 100000000, ss = 0.4734000E+09, time = 0.187 (s)
IF-Goto2: N = 100000000, ss = 0.4734000E+09, time = 0.204 (s)
IF-ELSE: N = 100000000, ss = 0.4734000E+09, time = 0.188 (s)

SELECT-CASE: N = 200000000, ss = 0.9468000E+09, time = 0.362 (s)
F77-GOTO: N = 200000000, ss = 0.9468000E+09, time = 0.425 (s)
IF-Goto1: N = 200000000, ss = 0.9468000E+09, time = 0.365 (s)
IF-Goto2: N = 200000000, ss = 0.9468000E+09, time = 0.403 (s)
IF-ELSE: N = 200000000, ss = 0.9468000E+09, time = 0.376 (s)

SELECT-CASE: N = 300000000, ss = 0.1420200E+10, time = 0.558 (s)
F77-GOTO: N = 300000000, ss = 0.1420200E+10, time = 0.639 (s)
IF-Goto1: N = 300000000, ss = 0.1420200E+10, time = 0.561 (s)
IF-Goto2: N = 300000000, ss = 0.1420200E+10, time = 0.653 (s)
IF-ELSE: N = 300000000, ss = 0.1420200E+10, time = 0.571 (s)

SELECT-CASE costs totally 1.114 (s)
F77-GOTO costs totally 1.278 (s)
IF-Goto1 costs totally 1.113 (s)
IF-Goto2 costs totally 1.260 (s)
IF-ELSE costs totally 1.135 (s)
Total time: 5.900 (s)
----------------------------------------------------------------------
$ gfc --version
GNU Fortran (GCC) 4.8.5
...

Tran Quoc Viet

unread,
Dec 5, 2017, 3:10:07 AM12/5/17
to
On Tuesday, December 5, 2017 at 12:50:42 PM UTC+7, Ev. Drikos wrote:
> On 05/12/2017 06:19, Tran Quoc Viet wrote:
> > ...
>
> The first test below has been compiled with the option -fno-align-jumps,
> as mentioned in GNU Bugzilla.
>
(snip)
>
> SELECT-CASE costs totally 1.301 (s)
> F77-GOTO costs totally 1.081 (s)
> IF-Goto1 costs totally 1.230 (s)
> IF-Goto2 costs totally 1.136 (s)
> IF-ELSE costs totally 1.165 (s)
> Total time: 5.913 (s)
> ----------------------------------------------------------------------

Yes. It's quite similar to my results. Could you run with larger values of N? say 9000000000.

robin....@gmail.com

unread,
Dec 5, 2017, 3:23:17 AM12/5/17
to
Wouldn't you say that your remark is entirely irrelant.
Since then there's been FORTRAN 77, Fortran 90, Fortran 95, Fortran 200x ....

Ellis Phillips & Lahey do not indicate any such restriction
in their Fortran 90 publication, and Silverfrost's F95 with strict language
checking accepts integer arguments.

Ev. Drikos

unread,
Dec 5, 2017, 3:29:08 AM12/5/17
to
The second test has better results and what you are asking causes an
overflow!

bartc

unread,
Dec 5, 2017, 7:18:14 AM12/5/17
to
On 05/12/2017 05:51, Ev. Drikos wrote:
> On 05/12/2017 06:19, Tran Quoc Viet wrote:
>> ...
>
> The first test below has been compiled with the option -fno-align-jumps,
> as mentioned in GNU Bugzilla.
>
> The second test has an extra "case" in the "select case" statement:
>   case (0)
>     error stop;
>
> Both test cases have been compiled with the much older (and much slower)
> 4.8 version and perhaps these tips are version specific. If both the
> option '-fno-align-jumps'  and the modification "case (0)" are omitted
> the "select-case" is much slower.
>

>    SELECT-CASE: N =   300000000, ss = 0.1420200E+10, time =    0.558 (s)
>       F77-GOTO: N =   300000000, ss = 0.1420200E+10, time =    0.639 (s)
>       IF-Goto1: N =   300000000, ss = 0.1420200E+10, time =    0.561 (s)
>       IF-Goto2: N =   300000000, ss = 0.1420200E+10, time =    0.653 (s)
>        IF-ELSE: N =   300000000, ss = 0.1420200E+10, time =    0.571 (s)
>
>     SELECT-CASE costs totally     1.114 (s)
>        F77-GOTO costs totally     1.278 (s)
>        IF-Goto1 costs totally     1.113 (s)
>        IF-Goto2 costs totally     1.260 (s)
>         IF-ELSE costs totally     1.135 (s)
>     Total time:    5.900 (s)

Just a note on these timings.

I've developed various compilers (not for Fortran), most recently for
x64 target.

I noticed that when implementing 'switch' (equivalent to select-case),
it was faster to just do sequential if-elsif tests whether there were
few cases, rather than use a jump-table and an indirect goto.

That limit was around 8 cases, about the same as the 8-10 used in these
Fortran tests.

I also noticed that using tables of label pointers, and doing an
indirect jump on that, was faster than using switch (for 200+ cases; I
haven't tested with small numbers). Such tables are the equivalent of
computed goto.

So with 8-10 cases, that might not be enough to make much of a
difference for select-case compared with other methods.

I guess I'd better put it to the test: increasing the number to 16 cases
(and using iand(i,15)+1 as the key), I get these results with Gfortran -O0:

SELECT-CASE costs totally 0.405 (s)
F77-GOTO costs totally 0.406 (s)
IF-Goto1 costs totally 0.718 (s)
IF-Goto2 costs totally 0.780 (s)
IF-ELSE costs totally 0.780 (s)

However if I now use -O3:

SELECT-CASE costs totally 0.374 (s)
F77-GOTO costs totally 0.577 (s)
IF-Goto1 costs totally 0.453 (s)
IF-Goto2 costs totally 0.452 (s)
IF-ELSE costs totally 0.453 (s)

(This is why I hate other people's optimising compilers! You've no idea
what's going on or what has been left out.)

Still, both sets of figures show that SELECT CASE was fastest, and
SELECT CASE is also the most natural way of writing such a multi-way
selection.

--
bartc

Tran Quoc Viet

unread,
Dec 5, 2017, 10:14:53 AM12/5/17
to
Dear Bartc,

Based on your idea, I make the branch to be wider, i.e. key = iand(i,31)+1. The results in my computer now are different with the one I claimed before.

Now I have to say that it's quite difficult to determine which one is the fastest. Is the SELECT-CASE? No, it's not true.

gfortran -O0: ./a.out 700000000 800000000 900000000

SELECT-CASE costs totally 29.582 (s)
F77-GOTO costs totally 28.139 (s)
IF-Goto1 costs totally 40.269 (s)
IF-Goto2 costs totally 48.823 (s)
IF-ELSE costs totally 49.823 (s)
Total time: 196.636 (s)
----------------------------------------------------------------------

gfortran -O3: ./a.out 700000000 800000000 900000000

SELECT-CASE costs totally 30.563 (s)
F77-GOTO costs totally 31.684 (s)
IF-Goto1 costs totally 21.883 (s)
IF-Goto2 costs totally 21.088 (s)
IF-ELSE costs totally 21.085 (s)
Total time: 126.303 (s)
----------------------------------------------------------------------

ifort -O0: ./a.out 700000000 800000000 900000000

SELECT-CASE costs totally 39.927 (s)
F77-GOTO costs totally 62.333 (s)
IF-Goto1 costs totally 39.229 (s)
IF-Goto2 costs totally 49.187 (s)
IF-ELSE costs totally 53.508 (s)
Total time: 244.184 (s)
----------------------------------------------------------------------

ifort -O3: ./a.out 700000000 800000000 900000000

SELECT-CASE costs totally 18.626 (s)
F77-GOTO costs totally 12.241 (s)
IF-Goto1 costs totally 21.026 (s)
IF-Goto2 costs totally 21.053 (s)
IF-ELSE costs totally 15.616 (s)
Total time: 88.561 (s)
----------------------------------------------------------------------


The test went with gfortran 4.9.2 and ifort 18.0.0, and run on Debian 8, in Laptop Intel(R) Core(TM) i3 CPU M 380 @ 2.53GHz.

Again, now the code looks more crazy.

!
! This test shows performance of the SELECT-CASE compared with
! other IF's types. Try on your computer and decide what shows
! the best performance.
!
program tt_select_case_02
implicit none
double precision x01,x02,x03,x04,x05,x06,x07,x08,x09,x10
double precision x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
double precision x21,x22,x23,x24,x25,x26,x27,x28,x29,x30
double precision x31,x32
double precision ss, st1, st2, st3, st4, st5
real dt2, dt1, dt3, dt4, dt5
integer t1, t2, clock_rate, clock_max
integer N, ten, i
integer j, key, narg
character(len=15) charg
!
! USAGE:
!
! Compiling:
! ifort -O3 tt_select_case.f90
! or
! gfortran -O3 tt_select_case.f90
!
! Executing:
! ./a.out 10000000 20000000 30000000
! or
! ./a.out 10000000 30000000 50000000 70000000 90000000
!
! wherein the loop size N will be read serially. We can input more.
! Make the list of N above to be longer to get a statistical test.
!
!
narg = command_argument_count()
!
if ( narg .lt. 1 ) then
write(*,'(a)') './a.out 10000000 30000000 50000000 70000000'
stop
endif
!
write(*,'(a,i3,/)' ) 'Number of values of N: ', narg
write(*,'(a,i20)' ) 'max integer 4-bytes =', huge(int(1,kind=4))
write(*,'(a,i20,/)') 'max integer 8-bytes =', huge(int(1,kind=8))
!
st1 = 0.0d0
st2 = 0.0d0
st3 = 0.0d0
st4 = 0.0d0
!
ten = 10
!
x01 = 1.234d0
x02 = 2.234d0
x03 = 3.234d0
x04 = 4.234d0
x05 = 5.234d0
x06 = 6.234d0
x07 = 7.234d0
x08 = 8.234d0
x09 = 9.234d0
x10 = 0.234d0
x11 = 1.456d0
x12 = 2.456d0
x13 = 3.456d0
x14 = 4.456d0
x15 = 5.456d0
x16 = 6.456d0
x17 = 7.456d0
x18 = 8.456d0
x19 = 9.456d0
x20 = 0.456d0
x21 = 1.678d0
x22 = 2.678d0
x23 = 3.678d0
x24 = 4.678d0
x25 = 5.678d0
x26 = 6.678d0
x27 = 7.678d0
x28 = 8.678d0
x29 = 9.678d0
x30 = 0.678d0
x31 = 0.888d0
x32 = 0.999d0
!
! 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 SELECT CASE: named 'SELECT-CASE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,31) + 1

select case (key)
case ( 1)
ss = ss + x01
case ( 2)
ss = ss + x02
case ( 3)
ss = ss + x03
case ( 4)
ss = ss + x04
case ( 5)
ss = ss + x05
case ( 6)
ss = ss + x06
case ( 7)
ss = ss + x07
case ( 8)
ss = ss + x08
case ( 9)
ss = ss + x09
case (10)
ss = ss + x10
case (11)
ss = ss + x11
case (12)
ss = ss + x12
case (13)
ss = ss + x13
case (14)
ss = ss + x14
case (15)
ss = ss + x15
case (16)
ss = ss + x16
case (17)
ss = ss + x17
case (18)
ss = ss + x18
case (19)
ss = ss + x19
case (20)
ss = ss + x20
case (21)
ss = ss + x21
case (22)
ss = ss + x22
case (23)
ss = ss + x23
case (24)
ss = ss + x24
case (25)
ss = ss + x25
case (26)
ss = ss + x26
case (27)
ss = ss + x27
case (28)
ss = ss + x28
case (29)
ss = ss + x29
case (30)
ss = ss + x30
case (31)
ss = ss + x31
case (32)
ss = ss + x32
end select
!
101 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt1 = real(t2-t1,8) / real(clock_rate,8)

st1 = st1 + dt1

write(*,1) 'SELECT-CASE:', N, ss, dt1
!
!
! 2) Testing Computed GOTO: named 'F77-GOTO'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,31) + 1

goto (901,902,903,904,905,906,907,908,909,910, &
911,912,913,914,915,916,917,918,919,920, &
921,922,923,924,925,926,927,928,929,930, &
931,932), key

goto 102

901 ss = ss + x01
goto 102
902 ss = ss + x02
goto 102
903 ss = ss + x03
goto 102
904 ss = ss + x04
goto 102
905 ss = ss + x05
goto 102
906 ss = ss + x06
goto 102
907 ss = ss + x07
goto 102
908 ss = ss + x08
goto 102
909 ss = ss + x09
goto 102
910 ss = ss + x10
goto 102
911 ss = ss + x11
goto 102
912 ss = ss + x12
goto 102
913 ss = ss + x13
goto 102
914 ss = ss + x14
goto 102
915 ss = ss + x15
goto 102
916 ss = ss + x16
goto 102
917 ss = ss + x17
goto 102
918 ss = ss + x18
goto 102
919 ss = ss + x19
goto 102
920 ss = ss + x20
goto 102
921 ss = ss + x21
goto 102
922 ss = ss + x22
goto 102
923 ss = ss + x23
goto 102
924 ss = ss + x24
goto 102
925 ss = ss + x25
goto 102
926 ss = ss + x26
goto 102
927 ss = ss + x27
goto 102
928 ss = ss + x28
goto 102
929 ss = ss + x29
goto 102
930 ss = ss + x30
goto 102
931 ss = ss + x31
goto 102
932 ss = ss + x32
goto 102
!
102 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt2 = real(t2-t1,8) / real(clock_rate,8)

st2 = st2 + dt2

write(*,1) 'F77-GOTO:', N, ss, dt2
!
!
! 3) Testing IF with Goto: named 'IF-Goto1'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,31) + 1

if ( key .eq. 1 ) goto 801
if ( key .eq. 2 ) goto 802
if ( key .eq. 3 ) goto 803
if ( key .eq. 4 ) goto 804
if ( key .eq. 5 ) goto 805
if ( key .eq. 6 ) goto 806
if ( key .eq. 7 ) goto 807
if ( key .eq. 8 ) goto 808
if ( key .eq. 9 ) goto 809
if ( key .eq. 10 ) goto 810
if ( key .eq. 11 ) goto 811
if ( key .eq. 12 ) goto 812
if ( key .eq. 13 ) goto 813
if ( key .eq. 14 ) goto 814
if ( key .eq. 15 ) goto 815
if ( key .eq. 16 ) goto 816
if ( key .eq. 17 ) goto 817
if ( key .eq. 18 ) goto 818
if ( key .eq. 19 ) goto 819
if ( key .eq. 20 ) goto 820
if ( key .eq. 21 ) goto 821
if ( key .eq. 22 ) goto 822
if ( key .eq. 23 ) goto 823
if ( key .eq. 24 ) goto 824
if ( key .eq. 25 ) goto 825
if ( key .eq. 26 ) goto 826
if ( key .eq. 27 ) goto 827
if ( key .eq. 28 ) goto 828
if ( key .eq. 29 ) goto 829
if ( key .eq. 30 ) goto 830
if ( key .eq. 31 ) goto 831
if ( key .eq. 32 ) goto 832

goto 103

801 ss = ss + x01
goto 103
802 ss = ss + x02
goto 103
803 ss = ss + x03
goto 103
804 ss = ss + x04
goto 103
805 ss = ss + x05
goto 103
806 ss = ss + x06
goto 103
807 ss = ss + x07
goto 103
808 ss = ss + x08
goto 103
809 ss = ss + x09
goto 103
810 ss = ss + x10
goto 103
811 ss = ss + x11
goto 103
812 ss = ss + x12
goto 103
813 ss = ss + x13
goto 103
814 ss = ss + x14
goto 103
815 ss = ss + x15
goto 103
816 ss = ss + x16
goto 103
817 ss = ss + x17
goto 103
818 ss = ss + x18
goto 103
819 ss = ss + x19
goto 103
820 ss = ss + x20
goto 103
821 ss = ss + x21
goto 103
822 ss = ss + x22
goto 103
823 ss = ss + x23
goto 103
824 ss = ss + x24
goto 103
825 ss = ss + x25
goto 103
826 ss = ss + x26
goto 103
827 ss = ss + x27
goto 103
828 ss = ss + x28
goto 103
829 ss = ss + x29
goto 103
830 ss = ss + x30
goto 103
831 ss = ss + x31
goto 103
832 ss = ss + x32
goto 103
!
103 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt3 = real(t2-t1,8) / real(clock_rate,8)

st3 = st3 + dt3

write(*,1) 'IF-Goto1:', N, ss, dt3
!
!
! 4) Testing IF with less Goto's: named 'IF-Goto2'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,31) + 1

if ( key .eq. 1 ) then
ss = ss + x01
goto 104
endif

if ( key .eq. 2 ) then
ss = ss + x02
goto 104
endif

if ( key .eq. 3 ) then
ss = ss + x03
goto 104
endif

if ( key .eq. 4 ) then
ss = ss + x04
goto 104
endif

if ( key .eq. 5 ) then
ss = ss + x05
goto 104
endif

if ( key .eq. 6 ) then
ss = ss + x06
goto 104
endif

if ( key .eq. 7 ) then
ss = ss + x07
goto 104
endif

if ( key .eq. 8 ) then
ss = ss + x08
goto 104
endif

if ( key .eq. 9 ) then
ss = ss + x09
goto 104
endif

if ( key .eq. 10 ) then
ss = ss + x10
goto 104
endif

if ( key .eq. 11 ) then
ss = ss + x11
goto 104
endif

if ( key .eq. 12 ) then
ss = ss + x12
goto 104
endif

if ( key .eq. 13 ) then
ss = ss + x13
goto 104
endif

if ( key .eq. 14 ) then
ss = ss + x14
goto 104
endif

if ( key .eq. 15 ) then
ss = ss + x15
goto 104
endif

if ( key .eq. 16 ) then
ss = ss + x16
goto 104
endif

if ( key .eq. 17 ) then
ss = ss + x17
goto 104
endif

if ( key .eq. 18 ) then
ss = ss + x18
goto 104
endif

if ( key .eq. 19 ) then
ss = ss + x19
goto 104
endif

if ( key .eq. 20 ) then
ss = ss + x20
goto 104
endif

if ( key .eq. 21 ) then
ss = ss + x21
goto 104
endif

if ( key .eq. 22 ) then
ss = ss + x22
goto 104
endif

if ( key .eq. 23 ) then
ss = ss + x23
goto 104
endif

if ( key .eq. 24 ) then
ss = ss + x24
goto 104
endif

if ( key .eq. 25 ) then
ss = ss + x25
goto 104
endif

if ( key .eq. 26 ) then
ss = ss + x26
goto 104
endif

if ( key .eq. 27 ) then
ss = ss + x27
goto 104
endif

if ( key .eq. 28 ) then
ss = ss + x28
goto 104
endif

if ( key .eq. 29 ) then
ss = ss + x29
goto 104
endif

if ( key .eq. 30 ) then
ss = ss + x30
goto 104
endif

if ( key .eq. 31 ) then
ss = ss + x31
goto 104
endif

if ( key .eq. 32 ) then
ss = ss + x32
goto 104
endif
!
104 continue
!
enddo

call system_clock ( t2, clock_rate, clock_max )

dt4 = real(t2-t1,8) / real(clock_rate,8)

st4 = st4 + dt4

write(*,1) 'IF-Goto2:', N, ss, dt4
!
!
! 5) Testing IF/ELSE: named 'IF-ELSE'
!
ss = 0.0d0

call system_clock ( t1, clock_rate, clock_max )

do i = 1,N

key = mod(i,31) + 1

if ( key .eq. 1 ) then
ss = ss + x01
else if ( key .eq. 2 ) then
ss = ss + x02
else if ( key .eq. 3 ) then
ss = ss + x03
else if ( key .eq. 4 ) then
ss = ss + x04
else if ( key .eq. 5 ) then
ss = ss + x05
else if ( key .eq. 6 ) then
ss = ss + x06
else if ( key .eq. 7 ) then
ss = ss + x07
else if ( key .eq. 8 ) then
ss = ss + x08
else if ( key .eq. 9 ) then
ss = ss + x09
else if ( key .eq. 10 ) then
ss = ss + x10
else if ( key .eq. 11 ) then
ss = ss + x11
else if ( key .eq. 12 ) then
ss = ss + x12
else if ( key .eq. 13 ) then
ss = ss + x13
else if ( key .eq. 14 ) then
ss = ss + x14
else if ( key .eq. 15 ) then
ss = ss + x15
else if ( key .eq. 16 ) then
ss = ss + x16
else if ( key .eq. 17 ) then
ss = ss + x17
else if ( key .eq. 18 ) then
ss = ss + x18
else if ( key .eq. 19 ) then
ss = ss + x19
else if ( key .eq. 20 ) then
ss = ss + x20
else if ( key .eq. 21 ) then
ss = ss + x21
else if ( key .eq. 22 ) then
ss = ss + x22
else if ( key .eq. 23 ) then
ss = ss + x23
else if ( key .eq. 24 ) then
ss = ss + x24
else if ( key .eq. 25 ) then
ss = ss + x25
else if ( key .eq. 26 ) then
ss = ss + x26
else if ( key .eq. 27 ) then
ss = ss + x27
else if ( key .eq. 28 ) then
ss = ss + x28
else if ( key .eq. 29 ) then
ss = ss + x29
else if ( key .eq. 30 ) then
ss = ss + x30
else if ( key .eq. 31 ) then
ss = ss + x31
else if ( key .eq. 32 ) then
ss = ss + x32

baf

unread,
Dec 5, 2017, 12:35:19 PM12/5/17
to
gfortran version 4.9 is ancient. Try a more recent version to provide a
better measure of a mature compiler as you have done with the Intel
compiler.

Terence

unread,
Dec 5, 2017, 4:33:19 PM12/5/17
to
After all the recent Forum comments on the computed GOTO,
please note that the original compilers up to my F77
always produced ASM code which executed the computed GOTO
" GOTO ( labels... ),i "
by loading i and testing with two instructions for 0>i<=n
where n was the count of labels as an immediate constant,
(and otherwise branching to the address of the following statement),
as one further single computer instruction:-
'branch indirect indexed' followed by a list of the
n addresses corresponding to the n indexing lables.

For n greater than three, I cannot see any faster method,
and is why that hardware 'branch indirect indexed' was devised.
Only one variable has to be loaded and tested, while all other
information is included as part of the compiled instructions.
Terence

Ev. Drikos

unread,
Dec 5, 2017, 6:08:02 PM12/5/17
to
On 05/12/2017 14:18, bartc wrote:
> On 05/12/2017 05:51, Ev. Drikos wrote:
>> ...
>>      Total time:    5.900 (s)
>
> Just a note on these timings.
>
> I've developed various compilers (not for Fortran), most recently for
> x64 target.
>
> I noticed that when implementing 'switch' (equivalent to select-case),
> it was faster to just do sequential if-elsif tests whether there were
> few cases, rather than use a jump-table and an indirect goto.
>
> That limit was around 8 cases, about the same as the 8-10 used in these
> Fortran tests.
>
> I also noticed that using tables of label pointers, and doing an
> indirect jump on that, was faster than using switch (for 200+ cases; I
> haven't tested with small numbers). Such tables are the equivalent of
> computed goto.
> > So with 8-10 cases, that might not be enough to make much of a
> difference for select-case compared with other methods.
>
Very interesting observations, thank you.

My point was that gfortran needs some assistance (case 0) to optimize
properly the "select type" statement". I don't know about "ifort". I
guess FSF documents or just can tell us how many entries fit in the jump
table of a switch statement.

Clearly, the particular test case can run faster the "select type"
statements rather the "if-else" statements. We agree!

Ev. Drikos

Terence

unread,
Dec 5, 2017, 10:23:33 PM12/5/17
to



Sorry! I note I had a typo! : correct range is 0<i<=n
as in the corrected reference:-

"by loading i and testing with two instructions for 0<i<=n"
Terence

Ev. Drikos

unread,
Dec 6, 2017, 1:19:17 AM12/6/17
to
On 05/12/2017 10:29, Ev. Drikos wrote:
> On 05/12/2017 10:10, Tran Quoc Viet wrote:
>> ...
>> Yes. It's quite similar to my results. Could you run with larger
>> values of N? say 9000000000.
>>
>
> The second test has better results and what you are asking causes an
> overflow!

This was a platform specific problem (darwin). In addition, there are
also performance fluctuations from version to version.

Each test below has run twice with gfortran 4.8 and 7.1

Ev. Drikos

------------------------------------------------------------------

Environment
-----------

Computer : Mac-Mini quad core i7 (Mid 2011)
RAM : 4-GB
Distro : RHEL 7.3 (Last Update on Aug 13, 2017)
Machine : x86_64-redhat-linux
Kernel Version : 3.10.0-693.5.2.el7.x86_64
System Compiler: gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)


$ diff -u select_case_32.f90 select_case0_32.f90
--- select_case_32.f90 2017-12-06 03:38:04.914997586 +0200
+++ select_case0_32.f90 2017-12-06 03:38:04.882997587 +0200
@@ -109,6 +109,8 @@
key = mod(i,31) + 1

select case (key)
+ case ( 0)
+ error stop;
case ( 1)
ss = ss + x01
case ( 2)
$ gfc -O3 select_case_32.f90 -o select_case_32
$ gfc -O3 select_case0_32.f90 -o select_case0_32
$ gfortran7 -O3 select_case0_32.f90 -o select_case0_32_7
$ gfortran7 -O3 select_case_32.f90 -o select_case_32_7
$ ./select_case_32 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 8.820 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 8.371 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.396 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.416 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.397 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 10.062 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 9.590 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.365 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 6.679 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.840 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 12.011 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 11.367 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 7.165 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 7.415 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 7.467 (s)

SELECT-CASE costs totally 30.893 (s)
F77-GOTO costs totally 29.328 (s)
IF-Goto1 costs totally 18.926 (s)
IF-Goto2 costs totally 19.510 (s)
IF-ELSE costs totally 19.704 (s)
Total time: 118.361 (s)
----------------------------------------------------------------------
$ ./select_case_32 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 9.529 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 9.041 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.907 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.915 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.803 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 10.711 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 9.535 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.128 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 6.149 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.137 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 11.288 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 10.769 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 6.901 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.918 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 6.926 (s)

SELECT-CASE costs totally 31.528 (s)
F77-GOTO costs totally 29.345 (s)
IF-Goto1 costs totally 18.936 (s)
IF-Goto2 costs totally 18.982 (s)
IF-ELSE costs totally 18.866 (s)
Total time: 117.657 (s)
----------------------------------------------------------------------
$ ./select_case0_32 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 3.599 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 2.029 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.341 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.358 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.373 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 4.109 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 2.323 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.113 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 6.117 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.142 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 4.627 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 2.608 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 6.870 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.898 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 6.955 (s)

SELECT-CASE costs totally 12.335 (s)
F77-GOTO costs totally 6.960 (s)
IF-Goto1 costs totally 18.324 (s)
IF-Goto2 costs totally 18.373 (s)
IF-ELSE costs totally 18.470 (s)
Total time: 74.462 (s)
----------------------------------------------------------------------
$ ./select_case0_32 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 3.612 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 2.031 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.348 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.359 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.383 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 4.133 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 2.332 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.124 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 6.116 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.156 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 4.645 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 2.620 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 6.905 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.902 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 6.945 (s)

SELECT-CASE costs totally 12.390 (s)
F77-GOTO costs totally 6.983 (s)
IF-Goto1 costs totally 18.377 (s)
IF-Goto2 costs totally 18.377 (s)
IF-ELSE costs totally 18.484 (s)
Total time: 74.611 (s)
----------------------------------------------------------------------
$ ./select_case_32_7 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 2.455 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 4.376 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.862 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.182 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.706 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 2.857 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 5.090 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.626 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 5.892 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.477 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 3.162 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 5.644 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 7.452 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.601 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 7.348 (s)

SELECT-CASE costs totally 8.474 (s)
F77-GOTO costs totally 15.110 (s)
IF-Goto1 costs totally 19.940 (s)
IF-Goto2 costs totally 17.675 (s)
IF-ELSE costs totally 19.531 (s)
Total time: 80.730 (s)
----------------------------------------------------------------------
$ ./select_case_32_7 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 2.480 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 4.393 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.819 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.153 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.697 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 2.816 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 5.033 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.632 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 5.874 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 6.514 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 3.161 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 5.739 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 8.393 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 7.334 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 8.096 (s)

SELECT-CASE costs totally 8.457 (s)
F77-GOTO costs totally 15.165 (s)
IF-Goto1 costs totally 20.844 (s)
IF-Goto2 costs totally 18.361 (s)
IF-ELSE costs totally 20.307 (s)
Total time: 83.134 (s)
----------------------------------------------------------------------
$ ./select_case0_32_7 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 3.256 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 2.582 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.837 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.152 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.139 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 3.689 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 2.929 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.683 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 5.926 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 5.952 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 4.158 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 3.294 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 7.490 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.609 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 6.601 (s)

SELECT-CASE costs totally 11.103 (s)
F77-GOTO costs totally 8.805 (s)
IF-Goto1 costs totally 20.010 (s)
IF-Goto2 costs totally 17.687 (s)
IF-ELSE costs totally 17.692 (s)
Total time: 75.297 (s)
----------------------------------------------------------------------
$ ./select_case0_32_7 700000000 800000000 900000000
Number of values of N: 3

max integer 4-bytes = 2147483647
max integer 8-bytes = 9223372036854775807

SELECT-CASE: N = 700000000, ss = 0.3377342E+10, time = 3.276 (s)
F77-GOTO: N = 700000000, ss = 0.3377342E+10, time = 2.591 (s)
IF-Goto1: N = 700000000, ss = 0.3377342E+10, time = 5.839 (s)
IF-Goto2: N = 700000000, ss = 0.3377342E+10, time = 5.191 (s)
IF-ELSE: N = 700000000, ss = 0.3377342E+10, time = 5.191 (s)

SELECT-CASE: N = 800000000, ss = 0.3859819E+10, time = 3.694 (s)
F77-GOTO: N = 800000000, ss = 0.3859819E+10, time = 2.934 (s)
IF-Goto1: N = 800000000, ss = 0.3859819E+10, time = 6.676 (s)
IF-Goto2: N = 800000000, ss = 0.3859819E+10, time = 5.876 (s)
IF-ELSE: N = 800000000, ss = 0.3859819E+10, time = 5.875 (s)

SELECT-CASE: N = 900000000, ss = 0.4342297E+10, time = 4.180 (s)
F77-GOTO: N = 900000000, ss = 0.4342297E+10, time = 3.295 (s)
IF-Goto1: N = 900000000, ss = 0.4342297E+10, time = 7.495 (s)
IF-Goto2: N = 900000000, ss = 0.4342297E+10, time = 6.585 (s)
IF-ELSE: N = 900000000, ss = 0.4342297E+10, time = 6.594 (s)

SELECT-CASE costs totally 11.150 (s)
F77-GOTO costs totally 8.820 (s)
IF-Goto1 costs totally 20.010 (s)
IF-Goto2 costs totally 17.652 (s)
IF-ELSE costs totally 17.660 (s)
Total time: 75.292 (s)
----------------------------------------------------------------------
$

Davs

unread,
Jan 17, 2018, 11:03:17 PM1/17/18
to
On Wednesday, June 22, 2016 at 10:47:58 PM UTC+8, 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...?

it depend upon compiler.

0 new messages