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
|