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 |