openMP fortran 回文数ソースプログラム

Last update:2018/03/06    Build:2018/03/06
! cpu を マルチで使う
! openmpを使ってみる do文を実行 -->
! 2018/2/16 read文で引っかかる。open文のみはOK
! なぜか? openmpを使わない場合のread文はOK
! 8バイト精度整数 integer(i_8)をやめることで実行可能となった --> 2018/2/17
!
! 8バイト精度整数 integer(i_8)が使えないので倍精度実数でかけ算を行う
! 1031130番目までの素数を全て読み込み倍精度でかけ算を行う
! 2018/2/17  100万個を読み込むとエラーがでるので 20万個で試す
!      うまくいかない。エラーで止まる
! appcrash c00000fd  00002b73
!  [見解]例外コード:ソフトウェア例外「0xC00000FD」は、
! Windowsアプリケーション実行時にスタックオーバーフローエラーが発生したことを意味しています。
!      ↓
! 動的に割り当てるとスタックを使わないとの記述があり試してみる (2018/2/19→ 
! うまくいった。エラーが出ない(2018/2/19)
!
! 回文のチェック
! 2018/2/19 --> OK
! ただし、複数のCPUを動かしてファイルアウトプットを行うと、おかしくなる
!
! privite変数を使うことと、共通変数を使うために排他的使用(critical)
! を使ってみる(2018/2/20)
! 実行はするが、回文数がマイナスになってエラーとなる。intがおかしいようだ
! 出力のフォーマット文で回文数のI22をF25.0に変更してOK
!
! 3万番目まで計算するとエラーがでる
! 倍精度実数の切り捨てにint()を使っていたのをaint()に変更してみる openmp-13.f90
! うまくいった。(2018/2/20)  -->素数20万番目の積まで回文数をチェック(openmp-16.f90)
!
! 2018/2/21 -->
! openmp-17.f90 スケジュールをダイナミックでスレッドを均等化 schedule
!  openmp-20.f90 schedule( dynamic 5000 )
!
! 2018/3/6  --> 
! openmp-21.f90 実時間とcpu-timeの測定を区別した
! openmp-21-1.f90  schedule ( dynamic )



program helloOpenMP
!$ use omp_lib

implicit none

character(30) seki,fmt,fmt2
integer , parameter :: i_8=8                       ! 8バイト型の整数をためす
integer(i_8) , parameter :: i_prime_end  = 1031130 ! 素数の最後の番数(○番目) 2018/2/19
integer :: i_long                                  ! 8バイト型整数の宣言 18桁まで
integer :: kosu
integer :: i_p_end       =  70000  ! 仮の最後

integer , allocatable :: i_prime(:)   ! 配列の動的割り当て  i_prime_end(1031130)番目までの素数を入れる 2018/2/19
integer , allocatable :: m_n(:,:)     ! 配列の動的割り当て  回文数となるm、nを入れる  2018/2/19
double precision , allocatable :: kaibun(:)        ! 配列の動的割り当て  回文数を入れる  2018/2/19

integer :: i_prime_tochu = 1031110                 ! 素数の途中の番数(○番目)
integer :: kazu = 0      !  回文数の数をカウント
integer i,j,k,l,l2,m,n   ! 9桁まで
integer  dmy             ! 試験用
double precision  dd ,ddd,ww,rev

! 時間関係の変数宣言
integer::time_ini   ! 経過時間の初期値
real::cpu_t0        ! cpu time 初期値
integer::flag       ! 0:初期値設定   0以外:今の時刻と初期値からの差



allocate( i_prime( i_prime_end ) )  !  動的に割り当てる スタックを使わない
allocate( m_n( i_prime_end,2 ) )    !  動的に割り当てる スタックを使わない
allocate( kaibun( i_prime_end ) )   !  動的に割り当てる スタックを使わない

fmt='(i8,i8,i10,i8,i10,"  ",f25.0)'
fmt2='(i10)'

call time_now("start",time_ini,cpu_t0,0)  ! 時間計測開始



open(51,file='prime_1600.txt',status='old',err=100)

do  i=1 , i_prime_end       ! ファイルを読み込むとエラーが出る
!  read(51,*) dmy           ! dmyに読み込むのではエラーなし
   read(51,*) i_prime(i)    ! ここをコメントアウトするとエラーなし
end do

close(51)

! 途中時間計測
call time_now("openMP start",time_ini,cpu_t0,1)  ! 途中時間計測



kosu=0
!  素数のかけ算の繰り返しで時間計測
!$omp parallel  private(dd,ddd,rev,ww) 
!$omp do schedule( dynamic,1000 ) 
!         !$omp do  
do m=1,i_p_end
  do n=m,i_p_end
    dd =dble(i_prime(m) ) * dble(i_prime(n) )
    ddd=dd
    rev=0
    do while ( ddd>0 )        ! 数字を逆転する
      ww=aint(ddd/10)
      rev=rev * 10 + (ddd - 10*ww )
      ddd=ww
    end do  
    if ( rev == dd ) then     ! 回文数か?
!$omp critical
      kosu= kosu + 1
      m_n( kosu ,1)=m
      m_n( kosu ,2)=n
      kaibun( kosu ) = dd
!$omp end critical
    end if

  end do     ! n
end do       ! m
!$omp end do
!$omp end parallel

! 途中時間計測
call time_now("openMP finish",time_ini,cpu_t0,1)  ! 途中時間計測 並列処理終了

open(61,file='out.txt',status='replace',err=200)  ! 結果のファイル出力
do i=1,kosu
  write(61,fmt) i , m_n(i,1), i_prime(m_n(i,1)) ,m_n(i,2),i_prime(m_n(i,2)) , kaibun(i) 
end do
close(61)

! 時間計測終了
call time_now(" END ",time_ini,cpu_t0,1)          ! 終了時間計測

stop

100 write(*,*) "file open error"
stop

200 write(*,*) "output file open err"
stop

end


subroutine time_now(moji,time_ini,cpu_t0,flag)    ! ====== 時間計測のためのサブルーチン ======
!呼び出し フォーマット
!call time_now("文字列",time_ini,cpu_t0,flag)
! 文字列 任意の文字列 そのまま出力
! time_ini   計測時間の初期値をやりとり用
! cpu_t0     cpu時間の初期値のやりとり用
! flag       0 : 初期値を設定する 0以外:初期値以外での時間計測

  implicit none
  character(*),intent(in)::moji
  integer::time_ini
  real::cpu_t0
  integer::flag         !  0:初期値設定   0以外:今の時刻と初期値からの差

  integer::ti(1:8)
  character(10)::b(1:3)
  real::cpu_t2
  integer::tf,tr !  tf: 経過時 time, tr: time rate

if ( flag==0 ) then
    call cpu_time(cpu_t0)           !  cpu time 初期化
    call system_clock(time_ini)     !  時間計測 初期化

    call date_and_time(b(1),b(2),b(3),ti)  ! 日時表示 初期
    write(6,*)
    write(6,'(3A,i0,A,i0,A,i0,A,i0,A,i0,A,i0,A)')"  == ", &
       moji," ",ti(1),"/",ti(2),"/",ti(3), &
       "  ",ti(5),":",ti(6),":",ti(7),"  (yyyy/mm/dd  hh:mm:ss)"
    write(6,*)

  return
else
    call date_and_time(b(1),b(2),b(3),ti) ! 日時表示
    write(6,*)
    write(6,'(3A,i0,A,i0,A,i0,A,i0,A,i0,A,i0,A)')"  == ", &
       moji," ",ti(1),"/",ti(2),"/",ti(3), &
       "  ",ti(5),":",ti(6),":",ti(7),"  (yyyy/mm/dd  hh:mm:ss)"

    call cpu_time(cpu_t2)  !  cpu timeの計測
    write(6,'(f10.3,A)')(cpu_t2-cpu_t0),"[cpu_time sec]"

    call system_clock(tf,tr) ! 経過時間の計測
    write(6,'(f10.3,A)')(tf-time_ini)/dble(tr),"[sec]"
  return
endif
end subroutine time_now

電子工作へ     HomePage     このページのトップ