A do-variable within a DO body shall not appear in a variable definition context. [I]

A do-variable within a DO body shall not appear in a variable definition context. [I]

Ritratto di emreka82

I have a code in which I wolud like to define i as the end value, let me make it clear by writing here:

 

integer function cornerio
real    :: term1, term2, term3, term4
do i=1,nelem
!......
if(abs(term1)<=1e-20) then
term1=0.
end if
if(abs(term2)<=1e-20) then
term2=0.
end if
if(abs(term3)<=1e-20) then
term3=0.
end if
if(abs(term4)<=1e-20) then
term4=0.
end if
if( term1==0 .and. term2==0 .and. term3==0 .and. term4==0 ) then
cornerio=-1
i=nelem 
else
if(term1/=0) then
if((term1*term2)>=0 .and. (term1*term3)>=0 .and. (term1*term4)>=0) then
cornerio=-1
i=nelem
end if
else if(term2/=0) then
if((term2*term1)>=0 .and. (term2*term3)>=0 .and. (term2*term4)>=0) then
cornerio=-1
i=nelem
end if
else if(term3/=0) then
if((term3*term1)>=0 .and. (term3*term2)>=0 .and. (term3*term4)>=0) then
cornerio=-1
i=nelem
end if
else if(term4/=0) then
if((term4*term1)>=0 .and. (term4*term2)>=0 .and. (term4*term3)>=0) then
cornerio=-1
i=nelem
end if
else 
print*, "ERROR"
end if
end if 
end do
return
end function cornerio

When I compile this simple code, I got the error "A do-variable within a DO body shall not appear in a variable definition context.   [I]" for the lines including "i=nelem". How can I solve this problem, without changing the logic ( İ=nelem inside the if-else statements). Thanks..

Emre

15 post / 0 new
Ultimo contenuto
Per informazioni complete sulle ottimizzazioni del compilatore, consultare l'Avviso sull'ottimizzazione
Ritratto di D.W. van Meeuwen

Dear Emre,

You cannot change the counting variable using an assignment within a DO-loop. What you are trying to do in my opinion is leaving the DO-loop by setting the counter to the max. The correct way to exit a DO loop is the EXIT statement.
If this is not what you want, you might have a look at DO WHILE

Dirk

Ritratto di Les Neilson

Emre
In the code you supplied you replace the i=nelem statement with either
return
or
exit

RETURN will return from the function
but if you have any code you want executed after the end of the do-loop then
EXIT will end the do-loop

If you have nested do-loops then you can name each loop and exit "loop-name" will end that particular loop.
See the help for EXIT Statement.

Les

Ritratto di emreka82

Quote:

D.W. van Meeuwen wrote:

Dear Emre,

You cannot change the counting variable using an assignment within a DO-loop. What you are trying to do in my opinion is leaving the DO-loop by setting the counter to the max. The correct way to exit a DO loop is the EXIT statement.
If this is not what you want, you might have a look at DO WHILE

Dirk


Thanks for a quick answer Dirk, the interesting thing is when I wrote exactly the same code in C++, I did not encounter any problem. I will try EXIT statement ( is it solely EXIT, or do I need any information (such as "go to" statement)), I think that do-while is more reliable solution. Thanks again for these ideas Dirk.
Ritratto di emreka82

That is the solution:

integer function cornerio
real    :: term1, term2, term3, term4
i=1
do while (i==nelem)
!......
if(abs(term1)<=1e-20) then

term1=0.

end if

if(abs(term2)<=1e-20) then

term2=0.

end if

if(abs(term3)<=1e-20) then

term3=0.

end if

if(abs(term4)<=1e-20) then

term4=0.

end if
if( term1==0 .and. term2==0 .and. term3==0 .and. term4==0 ) then

cornerio=-1

i=nelem

else

if(term1/=0) then

if((term1*term2)>=0 .and. (term1*term3)>=0 .and. (term1*term4)>=0) then

cornerio=-1

i=nelem

end if
else if(term2/=0) then

if((term2*term1)>=0 .and. (term2*term3)>=0 .and. (term2*term4)>=0) then

cornerio=-1

i=nelem

end if
else if(term3/=0) then

if((term3*term1)>=0 .and. (term3*term2)>=0 .and. (term3*term4)>=0) then

cornerio=-1

i=nelem

end if
else if(term4/=0) then

if((term4*term1)>=0 .and. (term4*term2)>=0 .and. (term4*term3)>=0) then

cornerio=-1

i=nelem

end if
else

print*, "ERROR"

end if
end if 
i=i+1

end do
return
end function cornerio

Ritratto di Les Neilson

If you have reached a required condition within the do-loop then exit is what you need.
In this instance (and generally speaking most of the time) you do not need a "go to".
Les

Ritratto di emreka82

Quote:

Les Neilson wrote:

Emre
In the code you supplied you replace the i=nelem statement with either
return
or
exit

RETURN will return from the function
but if you have any code you want executed after the end of the do-loop then
EXIT will end the do-loop

If you have nested do-loops then you can name each loop and exit "loop-name" will end that particular loop.
See the help for EXIT Statement.

Les

Also, thank you Les. There are a few solutions, I choose do-while as you can see above, it is correct right ?

Ritratto di Les Neilson

1. In the code you have shown nelem is not declared nor assigned a value.
2. The do while will execute once ONLY if nelem has the value 1 (At the end of the if statements i is increased by 1 and no longer equals nelem)
3. If nelem has a value other than 1 the loop will not execute at all.

Les

Ritratto di Steve Lionel (Intel)

Quote:

emreka82 wrote:

the interesting thing is when I wrote exactly the same code in C++, I did not encounter any problem.

That's because C++ is not Fortran. While a C++ "for" loop might look similar to a Fortran DO loop, and in many cases they are interchangeable, the semantics are really quite different.

A C/C++ for loop is much more like the Fortran DO WHILE - you specify start and end conditions and an expression that changes the loop variable each iteration. The end condition is an expression that is evaluated each time through the loop, and the increment variable is just that, a variable.

In a regular Fortran DO loop, it is in effect a counted loop where the count is determined before the loop ever starts execution, according to a formula specified in the standard. Once the loop begins execution, the count cannot be changed (at least not if you're following the standard.) In older compilers, you could sometimes change the loop control variable and have the effect you wanted, but most modern optimizing compilers don't let you do this.

The suggestions to use EXIT (also look up CYCLE) are the right way to go if you want to prematurely exit a loop (or skip iterations.)

Steve
Ritratto di jimdempseyatthecove

>>do while (i==nelem)
do while(i .LE. nelem)

using exit or return is much clearer.
In C/C++ wouldn't you use "break;"?

Jim Dempsey

www.quickthreadprogramming.com
Ritratto di emreka82

I read all the comments, yeah do-while does not provide the same outputs, exit can be more reliable option.

Quote:

Steve Lionel (Intel) wrote:

Quote:

emreka82 wrote:

the interesting thing is when I wrote exactly the same code in C++, I did not encounter any problem.

That's because C++ is not Fortran. While a C++ "for" loop might look similar to a Fortran DO loop, and in many cases they are interchangeable, the semantics are really quite different.

A C/C++ for loop is much more like the Fortran DO WHILE - you specify start and end conditions and an expression that changes the loop variable each iteration. The end condition is an expression that is evaluated each time through the loop, and the increment variable is just that, a variable.

In a regular Fortran DO loop, it is in effect a counted loop where the count is determined before the loop ever starts execution, according to a formula specified in the standard. Once the loop begins execution, the count cannot be changed (at least not if you're following the standard.) In older compilers, you could sometimes change the loop control variable and have the effect you wanted, but most modern optimizing compilers don't let you do this.

The suggestions to use EXIT (also look up CYCLE) are the right way to go if you want to prematurely exit a loop (or skip iterations.)

Steve,
But a regular do while loop of C++ should have the same effect of do while-loop of fortran, right ? I mean both the figurative and the output of them. Such as;
C++:


int i=0;

do

{

	i++;

	cout<<"i:"<
	cout<
	cout<
} while((max*bodydiv)<=(domsize/pow(2.,unidiv+i)));

Fortran:


i=1
do  while((max*bodydiv)<=(domsize/(2.**(unidiv+i))))

	i=i+1

    print*, "i:", i

    print*, max*bodydiv

    print*, domsize/(2**(unidiv+i))

end do

Ritratto di emreka82

Sorry for the c++ code above, I cannot write it inside the cpp code brackets.

Ritratto di emreka82

Another thing came to my mind: Is there a difference between exit(EXIT_FAILURE); of C++ and exit of Fortran ? If so, then what should I use to have the same effect of exit(EXIT_FAILURE); in Fortran ?

Ritratto di IanH

Quote:

emreka82 wrote:...
But a regular do while loop of C++ should have the same effect of do while-loop of fortran, right ? I mean both the figurative and the output of them. Such as;
C++:

int i=0;

do

{

	i++;

	cout<<"i:"<

	cout<

	cout<

} while((max*bodydiv)<=(domsize/pow(2.,unidiv+i)));


i=1

do  while((max*bodydiv)<=(domsize/(2.**(unidiv+i))))

    i=i+1

    print*, "i:", i

    print*, max*bodydiv

    print*, domsize/(2**(unidiv+i))

end do

In C in a do statement, the evaluation of the controlling expression (the loop continuation test) takes place after each execution of the loop body (the loop body of the statement is always executed at least once). In Fortran in the DO WHILE form, the expression in the WHILE is tested before any statements in the body of the construct is executed (the loop body may not be executed).

You might find some differences in the initial value of i between your two examples too.

Ritratto di MarkLewy

Quote:

emreka82 wrote:

Another thing came to my mind: Is there a difference between exit(EXIT_FAILURE); of C++ and exit of Fortran ? If so, then what should I use to have the same effect of exit(EXIT_FAILURE); in Fortran ?

Yes, they are different.
The Fortran exit statement is equivalent to C/C++ break statement.
The nearest equivalent to C/C++ exit() is the Fortran stop statement; 'stop 1' is equivalent to exit(EXIT_FAILURE).

Accedere per lasciare un commento.