IT pass HikiWiki - [itbase2020]Fortran random_number の説明 Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

Fortran では, 乱数を生成するために, random_number というサブルーチンが用意されています.

  real :: x                 ! 乱数受け取り用の変数の宣言

  ...

  call random_number( x )   ! 1 つの乱数の生成

random_number は, サブルーチンと呼ばれるもので, 関数とは
少し違いますが似たようなものです.
サブルーチンについては次回の実習で説明する予定ですが,
ひとまずここでは,

  call <サブルーチン名>

として呼び出して使えると考えておけばよいでしょう.

このサブルーチン random_number は, 0 から 1 までの実数の乱数を
生成します.
これを使ったプログラム例が以下です.

  program random

    implicit none

    real :: x               ! 乱数受け取り用の変数の宣言

    call random_number( x ) ! 1 つの乱数の生成
    write( 6, * ) x

  end program random

これを実行すると, 一つの数値が表示されます.

サブルーチン random_number は, call 1 回につき 1 つの乱数を返します.
したがって, N 回 call すれば N 個の乱数を生成します.
例えば, 下のように 3 回 call すれば, 3 つの乱数が表示されます.

    call random_number( x ) ! 1 つの乱数の生成
    write( 6, * ) x
    call random_number( x ) ! 1 つの乱数の生成
    write( 6, * ) x
    call random_number( x ) ! 1 つの乱数の生成
    write( 6, * ) x

では, 100 個の乱数を, その試行回数とともにファイルに保存する
プログラムを作りなさい. (出力結果の例は下を参照.)
また, その出力結果を使って gnuplot でグラフを描きなさい.
生成された乱数がランダムになっているように見えるかどうか確認しなさい.


== random_number に関する注意・補足

サブルーチン random_number は, 正確には乱数を生成していません.
これは, 疑似乱数と呼ばれるもので, 完全に偏りがないわけではありません.
したがって, 今後, 精密な計算を実行する際には, 別の手法で乱数を
生成する方が良いでしょう.

また, 上で説明した例のプログラムを何度も実行するとわかるように,
random_number を上に書いたように使うと, プログラムを実行するたびに
同じ乱数が生成されます.
これでは, データ処理・数値計算を行う上で困ることもあるでしょう.

プログラムの実行のたびに異なる乱数を生成するために, プログラム
実行ごとに異なる「種」を与えて乱数を生成する方法があります.
例えば, 下のようになります.

  program randomseed

    implicit none

    integer :: i
    real    :: x               ! 乱数受け取り用の変数の宣言

    integer              :: seedsize
    integer, allocatable :: seed(:)
    character(8)         :: date
    character(10)        :: time
    character(5)         :: zone
    integer              :: values(8)


    call random_seed(size=seedsize)                ! seed 配列のサイズを取得
    allocate( seed(seedsize) )                     ! seed 配列を割り付け
    call random_seed(get=seed)                     ! 乱数の種を取得
    call date_and_time( date, time, zone, values ) ! 現在時刻を取得
    seed(seedsize) = values(8)                     ! 現在時刻のミリ秒の数値を使って種を準備
    call random_seed( put=seed )                   ! 種を設定

    call random_number( x ) ! 1 つの乱数の生成
    write( 6, * ) x

  end program randomseed

上のプログラム例では, allocatable, allocate, random_seed, date_and_time など
のサブルーチン・関数を使っていますが, ここではそれらの詳細な説明は省きます.
興味があれば調べてみると良いでしょう.

いずれにしろ,

    call random_seed(size=seedsize)                ! seed 配列のサイズを取得

から

    call random_seed( put=seed )                   ! 種を設定

までが, 種を設定している部分です.