Restart a loop in Fortran - algorithm

I have an algorithm that looks like this:
10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then
go to 10
END IF
END DO
I want to restart the loop, when that if statement executes. However, I don't want to have to use a go to, I tried this:
10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then
I = 0; CYCLE
END IF
END DO
But then I get the error that I can't redefine the I variable, inside a loop. So I'm not sure how to approach this. Any help would be much appreciated

A conceptually simple way to phrase this problem is: "I want to repeat a loop until it completes, where there is some abort condition".
This "repeat until it completes" is idiomatically a do construct with indeterminate iterations:
do
... ! Our actions; we exit this outer loop when we are satisfied
end do
[This could also be phrased as a do-while loop.]
With the inner loop:
do
do i=1,10
... ! A conditional statement which aborts the inner loop
... ! And some actions
end do
! And once we're complete we exit the outer loop
end do
Now it's just a matter of handling "abort inner" and "exit outer". Here cycle and exit:
outer: do
print*, 'Start'
do i=1,10
print*, 'Step'
if (...) cycle outer ! Abort the inner loop
end do
exit outer ! The inner loop completed, so we're done
end do outer
The outer loop is labelled so that the cycle statement in the inner loop can reference it. Without that label the cycle will cycle the innermost loop containing it.

Likely a typo here somewhere, but this has some other ideas in a "do while" sense.
i.e. One could poll something coming in.
... USE ISO... etc stuff.
REAL(KIND=C_FLOAT), DIMENSION(10) :: A
LOGICAL(KIND=C_BOOL) :: Question1 = .TRUE.
LOGICAL(KIND=C_BOOL) :: Question2 = .TRUE.
INTEGER(KIND=C_INT) :: Index = 0
INTEGER(KIND=C_INT) :: I = 5
WRITE(*,*)'Enter first index to skip:"
READ(*,*) I
Outer_Loop: DO WHILE (Question1) ! .eq. .TRUE.
Inner_Loop: DO WHILE (Question2) ! .EQV. .TRUE.
Index = Index + 1
IF(Index > UBOUND(A,1)) THEN
Question1 = .FALSE.
Question2 = .FALSE.
Exit
ENDIF
IF(Index == I) EXIT
!Whatever like A(INdex) = something....
ENDDO Inner_Loop
IF(Question1) THEN !We must have more to possibly read or do...
WRITE(*,*)'Do more? 1=yes, 0=No"
READ(*,*) I
IF(I == 1) THEN
WRITE(*,*)'Enter next index to skip:"
READ(*,*) I
Question2 = .TRUE.
!and one can do a reset of I=0 here, which then becomes I=1 the next time through the inner loop...
ELSE
Question1 = .FALSE.
Question2 = .FALSE.
EXIT
ENDIF
ELSE !Must have gotten here to exit at the end of array?
EXIT
ENDIF
ENDDO Outer_Loop

I can suggest to ways of solving this issue: either use a while loop or a recursive function (highly depends on your actual algorithm). I am attaching a sample code for both cases (keep in mind that having variables with save qualifier is not the best idea, it's much better to do that with by passing variables as arguments to function - here it is used just for simplicity)
module functions
implicit none
integer :: restarted, save = 0
contains
recursive subroutine restart_loop
integer :: i
do i = 1, 10
print*, i
if ( i == 5 .and. restarted < 5 ) then
restarted = restarted + 1
call restart_loop
exit
end if
end do
end subroutine restart_loop
subroutine while_loop
integer :: i = 1
do while (i <= 10)
print*, i
if ( i == 5 .and. restarted < 5 ) then
i = 1
restarted = restarted + 1
end if
i = i + 1
end do
end subroutine while_loop
end module functions
program test_prog
use functions
implicit none
call while_loop
end program test_prog

Related

FORTRAN and MPI: allocate and initialize array of user-defined type using input file

I have an allocatable array of a user-defined type. The size of the array and the values of the array elements should be read in from a file. I have a serial code which looks something like this:
MODULE read_and_allocate
IMPLICIT NONE
TYPE my_type
INTEGER :: my_number
CHARACTER(10) :: my_string
CONTAINS
PROCEDURE :: read_my_type_from_string_array
PROCEDURE :: write_my_type
GENERIC :: WRITE(formatted) => write_my_type
END TYPE my_type
TYPE(my_type), ALLOCATABLE :: my_array(:)
CONTAINS
SUBROUTINE read_my_type_from_string_array(var, string_array)
CLASS(my_type), INTENT(INOUT) :: var
CHARACTER(*), INTENT(IN) :: string_array(:)
!code omitted
END SUBROUTINE read_my_type_from_string_array
SUBROUTINE write_my_type(var, funit, iotype, v_list, iostat, iomsg)
!code omitted
END SUBROUTINE write_my_type
SUBROUTINE read_my_array(var, funit)!, iotype, v_list, iostat, iomsg)
TYPE(my_type), ALLOCATABLE, INTENT(INOUT) :: var(:)
INTEGER, INTENT(IN) :: funit
CHARACTER(200) :: line
INTEGER :: rec_count, rec_len, max_rec_len
LOGICAL :: in_rec
INTEGER :: pos
CHARACTER(200),ALLOCATABLE :: rec(:)
INTEGER :: ii, jj
INTEGER :: status
! calling read_my_array deallocates var
IF (ALLOCATED(var)) DEALLOCATE(var)
max_rec_len = 0
rec_count = 0
in_rec = .FALSE.
DO
READ(funit, '(a)', iostat=status) line
IF (status < 0) EXIT
IF (in_rec .AND. TRIM(ADJUSTL(line)) == ']') THEN
in_rec = .FALSE.
END IF
IF (in_rec) THEN
rec_len = rec_len+1
END IF
IF (.NOT. in_rec .AND. TRIM(ADJUSTL(line)) == '[my_type') THEN
in_rec = .TRUE.
max_rec_len = MAX(max_rec_len, rec_len)
rec_len = 0
rec_count = rec_count + 1
END IF
END DO
ALLOCATE(rec(max_rec_len))
ALLOCATE(var(rec_count))
REWIND(funit)
in_rec = .FALSE.
jj = 1
DO
READ(funit, '(a)', iostat=status) line
IF (status < 0) EXIT
IF (in_rec .AND. TRIM(ADJUSTL(line)) == ']') THEN
CALL var(jj)%read_my_type_from_string_array(rec)
jj = jj + 1
in_rec = .FALSE.
END IF
IF (in_rec) THEN
rec(ii) = line
ii = ii+1
END IF
IF (.NOT. in_rec .AND. TRIM(ADJUSTL(line)) == '[my_type') THEN
in_rec = .TRUE.
rec(:) = ''
ii = 1
END IF
END DO
DEALLOCATE(rec)
END SUBROUTINE read_my_array
SUBROUTINE write_my_array(var, funit)
!code omitted
END SUBROUTINE write_my_array
END MODULE read_and_allocate
PROGRAM my_test
USE read_and_allocate
IMPLICIT NONE
INTEGER :: funit
OPEN(newunit=funit, file='input.txt')
CALL read_my_array(my_array, funit) !this routine allocates my_array
CALL write_my_array(my_array, 6)
END PROGRAM my_test
This works as expected (tested with gfortran on a mac). In short, read_my_array processes the given input file, infers the needed size (N) of my_array, allocates 'my_array', and then calls read_my_type_from_string_array N times to fill each element of my_array with data.
Now I want to port this code into an existing parallel program, but I'm not quite certain how to do this properly. I think I have two choices, but I have concerns about both of them:
1) I could read in the the text file only in the master process, but after reading this, I'm not sure if I can broadcast an allocatable array all that easily.
2) I could make each process read the text file separately, but I'm worried that I could create some kind of race condition (the function read_my_array uses REWIND and BACKSPACE), where different processes would get different results for my_array. I found this Intel forum thread where the SHARE option is mentioned for file-opening -- I'm not quite sure if this is what I'm looking for.
Is there a best practice how to do these kind of things?
EDIT:
An example input file would look something like this:
[my_type
my_string = 'one'
my_number = 1
]
[my_type
my_string = 'two'
my_number = 4
]
[my_type
my_string = 'alfred'
my_number = 7
]

Output of a fortran program into a variable

I have an interactive FORTRAN program that requires various inputs from the user. Now, I want to store the output of this Fortran program into a variable and use this value in a shell script. I tried
var=`./test` and var=$(./test)
but in both the cases, it does not prompt the user for input and stays idle. What should I do?
A piece of example fortran code is like this
test.f
program test
character*1 resp1, resp3
integer resp2, ans
write(*,*) 'Think of a prime number less than 10'
write(*,*) 'Say whether it is odd or even'
write(*,*) 'Write o/e'
read(*,*) resp1
if ( resp1 .EQ. 'e' ) then
ans=2
else
write(*,*) 'Is the number close to 4 or 8'
read (*,*) resp2
if ( resp2 == 8 ) then
ans=7
else
write(*,*) 'Is the number greater than or less than 4'
write(*,*) 'Write g or l'
read (*,*) resp3
if ( resp3 .EQ. 'l' ) then
ans=3
else
ans=5
end if
end if
end if
write(*,*) ans
end
Compiled as gfortran test.f -o test
Then I used a script like this
test.sh
var=`./test`
echo "The answer you are looking for is " $var
I believe there is something very trivial that I am not able to find. Please help me.
P.S. This is just an example code and script and my actual script and code is far different.
Jean-François Fabre is right.
program test
character*1 resp1, resp3
integer resp2, ans
write(0,*) 'Think of a prime number less than 10'
write(0,*) 'Say whether it is odd or even'
write(0,*) 'Write o/e'
read(5,*) resp1
if ( resp1 .EQ. 'e' ) then
ans=2
else
write(0,*) 'Is the number close to 4 or 8'
read (5,*) resp2
if ( resp2 == 8 ) then
ans=7
else
write(0,*) 'Is the number greater than or less than 4'
write(0,*) 'Write g or l'
read (5,*) resp3
if ( resp3 .EQ. 'l' ) then
ans=3
else
ans=5
end if
end if
end if
write(6,*) ans
end
Questions are stderr (0), Answers are stdin (5), Result is stdout (6)
var=`./test`
works fine after that.

how to use next on ruby for this case?

I'm learning Ruby On Rails program and I've came to a road block on one of the lessons. The assignment has me creating an odd numbers for the script to read starting from "20 to 0" using the next component. This is the example they've given me to change :
i = 20
loop do
i -= 1
print "#{i}"
break if i <= 0
end
This is the problem:
Add a line to your loop before your print statement. Use the next keyword so that you skip to the next iteration if the number i is odd.
How do I accomplish this?
You can just insert a next that skips the rest of the loop if the number is odd:
i = 20
loop do
i -= 1
next if i.odd?
puts "#{i}"
break if i <= 0
end
I would solve it this way:
i = 20
loop do
i -= 1
next if i%2 != 0
print "#{i}"
break if i <= 0
end
i = 20
loop do
i -= 1
next if i % 2 == 0
print "#{i}"
break if i <=1
end

searching a prime number

I hope I am not duplication any question but the suggested topic did not provide with any similar problem. I have a function that check if a number is a prime one. Now this is the slowest possible way to search for a prime.
subroutine is_prime_slow(num, stat)
implicit none
logical :: stat
integer :: num
integer :: i
if ((num .le. 3) .and. (num .gt. 1)) then
stat = .true.
return
end if
! write(*,*) 'limit = ',limit
do i = 2,num - 1
! write(*,*) 'mod(',limit,i,') = ',mod(limit,i)
if (mod(num,i) == 0) then
stat = .false.
return
end if
end do
stat = .true.
return
end
Now let's say that I do some improvement to it.
subroutine is_prime_slow(num, stat)
implicit none
logical :: stat
integer :: num
integer :: i
if ((num .le. 3) .and. (num .gt. 1)) then
stat = .true.
return
end if
! IMPROVEMENT
if ((mod(num,2) == 0) .or. (mod(num,3) == 0) .or. (mod(num,5) == 0) .or. (mod(num,7) == 0)) then
stat = .false.
return
end if
! write(*,*) 'limit = ',limit
do i = 2,num - 1
! write(*,*) 'mod(',limit,i,') = ',mod(limit,i)
if (mod(num,i) == 0) then
stat = .false.
return
end if
end do
stat = .true.
return
end
Now the second version excludes more than half of numbers e.g. all that are divisible by 2,3,5,7. How is it possible that when I time the execution with the linux 'time' program, the 'improved' version performs just as slowly? Am I missing some obvious trick?
Searching the first 900000 numbers:
1st: 4m28sec
2nd 4m26sec
The multiples of 2, 3, 5, and 7 are quickly rejected by the original algorithm anyway, so jumping over them does not improve the performance at all. Where the algorithm spends most of its time is in proving that numbers with large prime factors are composite. To radically improve the performance you should use a better primality test, such as Miller-Rabin.
A simpler improvement is testing factors only up to sqrt(num), not num-1. If that doesn't make immediate sense, think about how big the smallest prime factor of a composite number can be. Also, if you are looking for primes from 1 to N, it may be more efficient to use a prime number sieve, or testing divisibility only by primes you have already found.
I just recently coded something similar ;-)
! Algorithm taken from https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
subroutine eratosthenes_sieve(n, primes)
implicit none
integer,intent(in) :: n
integer,allocatable,intent(out) :: primes(:)
integer :: i, j, maxPrime, stat
logical :: A(n)
maxPrime = floor(sqrt(real(n)))
A = .true.
do i=2,maxPrime
j = i*i
do
A(j) = .false.
j = j + i ; if ( j .gt. n ) exit
enddo
enddo !i
allocate( primes( count(A)-1 ), stat=stat )
if ( stat /= 0 ) stop 'Cannot allocate memory!'
j = 1
do i=2,n ! Skip 1
if ( .not. A(i) ) cycle
primes( j ) = i
j = j + 1 ; if ( j > size(primes) ) exit
enddo
end subroutine
This algorithm gives you all prime numbers up to a certain number, so you can easily check whether your prime is included or not:
if ( any(number == prime) ) write(*,*) 'Prime found:',number

MATLAB: Does the If Statement order affect performance

I'm trying to speed up a loop that runs for about 100000 iterations and was wondering if the order of if statements had an effect on the performance. For example will the following code check the if and elseif before executing the statements in else every time it goes through the for loop?
for ii = 1:100000
if ii == 1
statements_1;
elseif ii >= 2 && ii <= 10
statements_2;
else
statements_3;
end
end
Will the below code run faster?
for ii = 1:100000
if ii > 10
statements_3;
elseif ii >= 2 && ii <= 10
statements_2;
else
statements_1;
end
end
Any help will be much appreciated
Yes, it will check the first condition fist, and then if it is false, it will check the following conditions.
However, to improve performance, I suggest you to use a more vectorized code:
for i=find(condition1(1:10000))
statements1
end
for i=find(condition2(1:10000))
statements2
end
for i=find(condition3(1:10000))
statements3
end
with for instance condition2=#(i) (i>2 & i<10)

Resources