Statement label in ENDDO not matching DO label - loops

I wrote a program to check if a number is prime or not.
Here is the code:
program prime
integer n,i
print *, 'enter a number'
read *,n
do 10,i=2,n-1
if(mod(n,i).eq.0.0) then
print*, 'it is not prime'
read*
stop
end if
continue
if(n.eq.i)print *, 'it is prime'
read *
stop
end do
end program
However, there was a problem. I got an error:
Error: Statement label in ENDDO doesn't match DO label
The error in itself was understandable, the end do was not connected with the do loop. However, I cannot connect it as the program will not let me do so. Why is this?

With the statement
do 10,i=2,n-1
you are introducing a labelled DO construct. A labelled DO construct needs an appropriate termination statement, with matching label. In current Fortran, a matching labelled DO construct is terminated with
10 end do
or
10 continue
Labelled DO constructs are obsolescent in current Fortran, so the entire DO construct of the question can instead be written as
do i=2,n-1
...
end do
In the question, there is horribly confusing indentation. The continue statement is perhaps intended as the termination of the loop, but it isn't because it isn't labelled 10. continue is just a normal, do nothing, statement which has significance as a loop termination only through its label. Instead, the compiler sees the loop terminated by the end do, regardless of indentation, and then complains because it's missing the appropriate label.
The logic of the loop agrees with the indentation: the continue statement should be the end of the loop. There are three options
add a label 10 to the statement
change the continue to 10 end do
remove the 10 from the DO statement and change continue to end do
For each option, also delete the second end do.
Finally, with
if(n.eq.i) ...
coming after the loop, that condition is redundant: i will always have value n if it's reached.

program prime
integer n,i
print*, 'enter a number'
read*,n
do i=2,n-1
if (mod(n,i)==0.0) then
print*, 'it is not prime'
read*
stop
end if
end do
if (n==i) then
print*, 'it is prime'
read*
endif
end program prime

Related

VBScript Error Handling in For Each loops [duplicate]

A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.

Program giving signal SIGABRT: Process abort signal in one code and does not in other code

I am trying to run this code but I am not getting why I m receiving SEGMENTATION error for the code?
Apparently, when I am setting the value of y equal to 2.718(equal to e) the code is running fine without any error. But when I change the value of y, the code gives me the segmentation error.
I tried the options of - fcheck for 'all' and 'bounds' both options but my device didnt return any error.
I am lot confused then, why the code is giving this error?? Please help me
program Trial
implicit none
integer :: i,j,L,a,b,c,d,niter,time,mm,nn,N,k,g1,g2,w ! n is iteration time
real :: r,h,E,Ei,Ef,f,E1,E2,S,y
real :: JE=1.0
integer, dimension(8) :: values
integer, dimension(:,:), allocatable :: spin
integer, dimension(:), allocatable :: seed
!integer, dimension(0:100) :: G, Hi
real, dimension(100) :: G,Hi,Hit, root
!integer, dimension(0:1) ::
character(len=30) :: charac_b
!seed=44589
charac_b = 'store_config'
print *,'Enter the number of lattice points:'
read *,L
print *, 'Enter number of iterations:'
read *,niter
!Initialisation of G & H. G is density of states and H is the Histogram
do i=1,101
G(i)=1.0
Hi(i)=0.0
Hit(i)=-200+4*(i-1)
end do
f=2.71828183
do i=1,21
root(i)=f
f=f**(0.5)
end do
! Min fn gives minimum of the value
allocate(spin(L,L))
E=0.0
S=0.0
N=L*L
!Generator of Random Numbers
call date_and_time(VALUES=values)
call random_seed(size=k)
allocate(seed(k))
seed(:)=values(:)
call random_seed(put=seed)
!Initialising Data
open(12,file="Data_initial.txt")
do i=1,L
do j=1,L
call RANDOM_NUMBER(r)
if(r<0.5) then
spin(i,j)=+1
else
spin(i,j)=-1
end if
write(12,*) float(i),float(j),float(spin(i,j))
end do
end do
close(12)
!Calculating energies
do i=1,L
do j=1,L
a=i+1;b=i-1;c=j+1;d=j-1
if(i==L)a=1
if(i==1)b=L
if(j==1)d=L
if(j==L)c=1
!M=M+spin(i,j)
E=E-JE*float((spin(i,j))*(spin(a,j)+spin(b,j)+spin(i,c)+spin(i,d)))
end do
end do
E=E*0.5
print *,'intial energy and per spin=',E,E/float(N)
!print *,'initial magnetisation and per spin=',M,mag
!Going for a random flipping now
!f=2.71828183
!do kt=1,21
y=root(2)
!y=2.5
do time=1,niter
do mm=1,L
do nn=1,L
call RANDOM_NUMBER(r); i=int(r*float(L))+1
call RANDOM_NUMBER(r); j=int(r*float(L))+1
a=i+1;b=i-1;c=j+1;d=j-1
if(i==L)a=1
if(i==1)b=L
if(j==1)d=L
if(j==L)c=1
Ei=-JE*float((spin(i,j))*(spin(a,j)+spin(b,j)+spin(i,c)+spin(i,d)))
spin(i,j)=-spin(i,j)
Ef=-JE*float((spin(i,j))*(spin(a,j)+spin(b,j)+spin(i,c)+spin(i,d)))
E1=E
E2=E1+(Ef-Ei)
g1=int((E1+200.0)/4)+1
g2=int((E2+200.0)/4)+1
if(g2<=g1) then
G(g2)=LOG(G(g2))+LOG(y)
!G(g2)=G(g2)*f
Hi(g2)=Hi(g2)+1
else
call RANDOM_NUMBER(h)
if(h<=G(g1)/G(g2)) then
G(g2)=LOG(G(g2))+LOG(y)
!G(g2)=G(g2)*f
Hi(g2)=Hi(g2)+1
else
G(g1)=LOG(G(g1))+LOG(y)
!G(g2)=G(g2)*f
Hi(g1)=Hi(g1)+1
spin(i,j)=-spin(i,j)
end if
end if
E=E2
end do
end do
end do
do i=1,101
S=S+(Hit(i)*Hi(i))
end do
do i=1,101
if(Hi(i) .lt. 0.95*(real(S/101.0))) then
print *,"No",i
exit
end if
end do
do j=1,101
Hi(j)=0.0
end do
!f=f**(0.5)
!end do
open(13,file="Data_final.txt")
do w=1,101
write(13,*) Hit(w), G(w), Hi(w)
end do
deallocate(spin)
deallocate(seed)
end program Trial
What you really have to do is to compile your program for error checking whenever you suspect a problem. I suggest to do it every time during development. Then, when asking here, you always have to report the complete program output, especially the complete error message. If you use the options I suggested in the comment
> gfortran -g -fbacktrace -Wall -fcheck=all spins.f90
and run the code, you have a lot of useful information
> ./a.out
Enter the number of lattice points:
5
Enter number of iterations:
1
At line 22 of file spins.f90
Fortran runtime error: Index '101' of dimension 1 of array 'g' above upper bound of 100
Error termination. Backtrace:
#0 0x7f4df5a28640 in ???
#1 0x7f4df5a29185 in ???
#2 0x7f4df5a2952a in ???
#3 0x400fee in trial
at spins.f90:22
#4 0x403f8c in main
at spins.f90:141
which really should be included in your question.
It points to a specific line of code. Even without the checking option you still get the backtrace which still points to the line of code.
#3 0x400fee in trial
at spins.f90:22
The output from the checking option is more specific.
Index '101' of dimension 1 of array 'g' above upper bound of 100
So the crash happens at the very begin
do i=1,101
G(i)=1.0
Hi(i)=0.0
Hit(i)=-200+4*(i-1)
end do
because the arrays are only declared from 0 to 100, not 101.
The value of y appears to be a red herring. Unfortunately, several points in your question confused me and lead to examining wrong parts of the code. You probably did not apply -=fcheck=all option correctly or you only applied it to a different version of the code. Be sure to use it always and to re-run your code after using it.

How to terminate a do loop?

I am writing a very basic Fortran Code to create the Ising model. However, I am stuck at the very last step - repeat the calculation until the most stable condition is achieved.
do
!Calculation (omitted here)
!Making a decision
if (E1 /= -64) then !not yet stable
if(dE > 0.0) then
call seed
call random_number(prob) ! random generate a number which is 0 <= Prob <= 1
Print *, prob
if(Prob < exp(-dE/T)) then
!do nothing as the flip was made
else
mat(b,c) = -mat(b,c) !flip the sign back, i.e. reject the change; only accept with probability of exp(-dE/T)
end if
else
end if !Since the sign has changed already, if dE<0, the move must be accepted. Therefore no additional move should be taken
else
end do
end if
end do
Apparently, Fortran doesn't like the second last end do statement as I didn't defined do at that particularly. All I want is to exit the do loop once E1 == -64.
In Fortran you can exit a do loop at any time using the exit statement.
do
...
if (condition) exit
end do
If your do loop is labelled, use the label in the exit statement too
outer: do
inner: do
...
if (condition) exit outer
end do inner
end do outer
Fortran 2008 allows the exit statement for other constructs too.
You should be able to use a while loop.
while (E1 [.ne. OR /=] -64) do
[your code]
end do
This requires E1 be updated inside the loop. Without this update, E1 will always not equal -64 and cause an infinite loop. Your code doesn't explicitly show this happening. I assume it does, but it's something to keep in mind.

Problem with Array Sorting and Printing it sideways in Fortran 95

I am trying to take my array of numbers based on a variable that determines its size and sort it.
The array is created using the random numbers seed on Fortran 95. However when I try to sort it I run into big trouble. It compiles fine, but the array is printed with a lot of asterisks in it.
In addition I wanted to print my array sideways, (for instance something like this: 1 2 3 4 etc.) but I even failed at doing that. I realize that it must be done using the Advance="no" within a DO loop, but apparently that is erroneous as well.
Below is the code that I am using. If anyone is willing to let me know where I may be wrong I would be very grateful. Thanks for your time.
SUBROUTINE Sorter(num, numinteger)
INTEGER, INTENT(OUT):: num(100)
INTEGER, INTENT(IN):: numinteger
DO i=1, (numinteger-1)
min=num(i)
pos=i
DO j=i,numinteger
IF (num(j)<min)THEN
min=num(j)
pos=j
END IF
END DO
temp=num(i)
num(i)=min
num(pos)=temp
END DO
PRINT*, " "
PRINT*, "Sorted Numbers"
DO i=1, numinteger
WRITE(*,23,ADVANCE="NO") num
23 FORMAT (I2)
END DO
END SUBROUTINE
Thanks!
You don't have any spaces between your numbers, but you are also looping over the array, but not incrementing an index... you are asking the computer to print the entire array on each interation.
I think this should be: WRITE(*,23,ADVANCE="NO") num(i)

Loops in ada and the implementation

Below is a piece of code shown and doubts are regarding the implementation of loops
C := character'last; --'// SO code colorizer hack
I := 1;
K : loop
Done := C = character'first; --'
Count2 := I;
Exit K when Done;
C := character'pred(c); --'
I := I + 1;
end loop K;
Can anyone please tell me what does 'K' stands for.I guess its not a variable.How does 'K' control the execution of the loop?
K is the name of the loop. The end loop and Exit statements refer to that name, to make it clear what loop is being exited.
The Ada Reference Manual calls it a "loop_statement_identifier".
As noted, K is the loop's label. It allows you to identify a particular loop to aid readability, and also to selectively exit a specific loop from a set of nested enclosing ones (i.e. being a "goto"...shhh! :-)
Here's a contrived example (not compiled checked):
S : Unbounded_String;
F : File_Type;
Done_With_Line : Boolean := False;
All_Done : Boolean := False;
begin
Open(F, In_File, "data_file.dat");
File_Processor:
while not End_Of_File(F) loop
S := Get_Line(F);
Data_Processor:
for I in 1 .. Length(S) loop
Process_A_Character
(Data_Char => Element(S, I), -- Mode in
Line_Done => Done_With_Line, -- Mode out
Finished => All_Done); -- Mode out
-- If completely done, leave the outermost (file processing) loop
exit File_Processor when All_Done;
-- If just done with this line of data, go on to the next one.
exit Data_Processor when Done_With_Line;
end loop;
end loop File_Processor;
Close(F);
end;
K is essentially the name of the loop. The exit k tells the code to stop looping and go to the next statement after loop k ends.
You usually don't need to name loops, as you can just say exit and it will exit the enclosing loop. However, if you have a loop nested inside another loop, and you'd like to exit not the one immediately around the exit statement, but the outermost one, then doing something like this may be required.
K is a label that names the loop. Wow, it has been a long time since I've seen any Ada...

Resources