Pergunta
Estou tentando executar esse código MPI fortran. Existem vários problemas:
1) Quando executo este código, espero que o programa escreva 'Digite o número de intervalos: (0 desmaios)' para que eu me pergunte n. Em vez disso, me pergunta n primeiro !!! porque?
2) Se eu não comentar a linha 'Goto 10', o programa continua me perguntando n para sempre e não me mostra mais nada !!!
3) Se eu comentar 'Goto 10', o programa me pergunte e depois gravará resultados. Mas, o problema é sempre que o programa escreve parte do resultado, não os resultados completos. Trunca a saída !! Abaixo estão a produção por três vezes consecutivos, executei o programa:
> mpiexec -n 40 ./a.out
10000000
Enter the number of intervals: (0 quits)
pi is 3.14159265358978 Error is 1.287858708565182E-014
time is 1.687502861022949E-002 seconds
> mpiexec -n 40 ./a.out
10000000
Enter the number of intervals: (0 quits)
pi is 3.14159265358978 Error is 1.287858708565182E-014
time is 1.68750286102
> mpiexec -n 40 ./a.out
10000000
Enter the number of intervals: (0 quits)
pi is 3.14159265358978 Error is 1.287858708565182E-014
time is 1.687502861022949E-002 se
Alguém tem alguma ideia do que está acontecendo? Agradeço sua ajuda com antecedência.
program main
use mpi
double precision starttime, endtime
double precision PI25DT
parameter (PI25DT = 3.141592653589793238462643d0)
double precision mypi, pi, h, sum, x, f, a
double precision starttime, endtime
integer n, myid, numprocs, i, ierr
f(a) = 4.d0 / (1.d0 + a*a) ! function to integrate
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
10 if ( myid .eq. 0 ) then
print *, 'Enter the number of intervals: (0 quits) '
read(*,*) n
endif
starttime = MPI_WTIME()
! broadcast n
call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)
! check for quit signal
if ( n .le. 0 ) goto 30
! calculate the interval size
h = 1.0d0/n
sum = 0.0d0
do 20 i = myid+1, n, numprocs
x = h * (dble(i) - 0.5d0)
sum = sum + f(x)
20 continue
mypi = h * sum
! collect all the partial sums
call MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0, &
MPI_COMM_WORLD,ierr)
! node 0 prints the answer.
endtime = MPI_WTIME()
if (myid .eq. 0) then
print *, 'pi is ', pi, 'Error is ', abs(pi - PI25DT)
print *, 'time is ', endtime-starttime, ' seconds'
endif
go to 10
30 call MPI_FINALIZE(ierr)
stop
end
Solução
Você precisa lavar explicitamente sua saída. Não me lembro se o Fortran tem função de descarga padrão, se não funcionar, tente Flush_.
Basicamente, o que acontece, seu processo zero buffers de saída e, a menos que o explicitamente diga para exibir, você acaba uma coisa engraçada
Outras dicas
Este programa foi projetado para fazer loop através do "Goto 10" no final. A única maneira de romper com isso é que N tenha um valor <= 0, que ativará o "Goto 30" e o ramo além do "Goto 10". Pistas adicionais de que essa é a intenção são o comentário "Verifique o sinal de desativação" e que o prompt para a entrada de n inclui "(0 desmaios)". Então tente inserir 0!
Este não é um bom exemplo de fortran moderno. Apesar de claramente usar um compilador Fortran 90 ou mais recente (a declaração "Uso" mostra isso), ele é escrito no estilo do Fortran 77 ou anterior. Layout de código fixo, com as linhas de origem aparentemente começando na coluna 7. Comente os caracteres na primeira coluna (o antigo fortran exigiu um C na primeira coluna). "Dupla precisão". Uso pesado de Gotos para a lógica do programa. (Na minha opinião, e outros podem discordar, há um lugar para a declaração de goto, mas não para o fluxo de controle básico de um programa.) Obsolete fortran (na minha opinião).
A maneira moderna fortran de expressar o fluxo básico:
MainLoop: do
.....
if (n .le. 0) exit MainLoop
....
end do MainLoop