外部ルーチン・外部関数 - external routines, external functions(Fortran 第7回)

←第6回 ファイル操作
→第8回 内部ルーチン・内部関数

はじめに

第7回は、外部ルーチン・外部関数です。
まったく怖がる必要はありません、ただ関数化してmain programの外に記述するだけの話です。

外部ルーチンとは

main programの外に記述して、main programや他のサブルーチンから呼び出すサブルーチンのことです。
なお、サブルーチンとはある特定のタスクを実行するコードのまとまりのことを指します。

外部関数とは

上との比較で説明すると、外部ルーチンは変数を修正したり、表示を行うもの(手続き的な処理)、外部関数は何らか計算をして値を返すものとしてしばしば用いられます。(サブルーチンと関数の違いに由来しています)

解説

外部ルーチンと外部関数を具体例を用いて解説します。

具体例1(外部ルーチン)

! subroutine_module.f90
subroutine greet(name)
    character(len=*), intent(in) :: name
    print *, 'Hello, ', trim(name), '!'
end subroutine greet

! main_program.f90
program main_program
    implicit none
    character(len=20) :: name

    ! Call the external subroutine
    name = 'John Doe'
    call greet(name)
end program main_program

上の例に関して補足します。
外部ルーチン内での引数の宣言は、
(引数の型), intent(_) :: name で行います。
intent(_)には種類があり、
intent(in): 引数は読み取り専用だよ、書き換えないよ
intent(out): 引数は書き込み専用だよ、書き換えるよ
intent(inout): 引数は読み書きできるよ、サブルーチン内で書き換えたりするけど、実行が終わったら元に戻すよ
という意味があります。

具体例2(外部関数)

! Define the external function
double precision function square(x)
    double precision, intent(in) :: x
    square = x * x
end function square

! Main program that calls the external function
program main
    implicit none
    double precision :: num, squared

    num = 5.0d0
    squared = square(num)
    print *, 'The square of ', num, ' is ', squared
end program main

まとめ

今回は外部ルーチン、外部関数について解説しました。サブルーチンは日本語でしばしば副ルーチンと呼ばれるということを最後に補足しておきます。
第8回は内部ルーチン・内部関数です。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第6回 ファイル操作
→第8回 内部ルーチン・内部関数

ファイル操作 - file handling(Fortran 第6回)

←第5回 多次元配列
→第7回 外部ルーチン・外部関数

はじめに

第6回はファイル操作です。
ファイル操作は言語によって結構書き方が異なったり、いろんなパラメータを設定できたりします。

ファイル操作の方法

ファイル操作は、open, read, write, closeを用いて行います。

具体例

program fileHandling
    implicit none
    integer :: unit_number = 10
    real :: temperature

    ! Open the file for reading
    open(unit=unit_number, file='temperatures.dat', status='old', action='read')

    ! Read the first temperature
    read(unit=unit_number, fmt=*) temperature
    print *, 'First temperature: ', temperature

    ! Close the file
    close(unit=unit_number)

    ! Open the file again for appending
    open(unit=unit_number, file='temperatures.dat', status='unknown', action='write', position='append')

    ! Write a new temperature to the file
    write(unit=unit_number, fmt=*) 'New temperature: 20.5'

    ! Close the file
    close(unit=unit_number)
end program fileHandling

unit: 開いたデータに対する固有の値。
file: ファイル名
status: oldは既存ファイル。unknownはファイルがなければwriteした内容でをファイルを作成。
position: 次の操作を行うポインタの位置、appendなら既存データの末尾の後ろ。

readの後の変数は、読み込んだ内容を代入する変数。
writeの後の内容は、ファイルに書き込む内容。

まとめ

今回はファイル操作について解説しました。コンソールからファイルに入力する操作は、普段あまり使わないし、今ファイルがどうなっているか書き込み中にリアルタイムでわからないので少し難しいですね。
第7回は外部ルーチン・外部関数です。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第5回 多次元配列
→第7回 外部ルーチン・外部関数

多次元配列 - multidimensional array(Fortran 第5回)

←第4回 書式設定
→第6回 ファイル操作

はじめに

第5回は多次元配列です。第3回の多重ループの解説の際に2次元の配列は登場しましたが、今回は多次元配列自体の説明と、3次元4次元の例も解説します。

多次元配列とは

多次元配列とは、複数のインデックスを持った配列のことで、例えばエクセルの表であれば2次元配列とみなすことができます。
物理空間を離散化した格子データのシュミレーション、ピクセルデータを扱う画像処理、線形代数など様々な場面で活用されています。

多次元配列の解説

reshapeを使うか、ループを使って作成します。
具体例1(3次元配列をreshapeを用いて作成)

program threeDimensionalArrayDeclaration
    implicit none
    integer, dimension(3, 3, 3) :: cube = reshape([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], [3, 3, 3])
    print *, 'Cube:'
    print *, cube
end program threeDimensionalArrayDeclaration

具体例2(4次元配列をreshapeを用いて作成)

program fourDimensionalArrayDeclaration
    implicit none
    integer, dimension(3, 3, 3, 3) :: hypercube = reshape([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81], [3, 3, 3, 3])
    print *, 'Hypercube:'
    print *, hypercube
end program fourDimensionalArrayDeclaration

具体例3(多重ループを用いて作成)

program threeDimensionalArrayDeclaration
    implicit none
    integer, dimension(3, 3, 3) :: cube
    integer :: i, j, k, count

    ! Initialize the cube using a counter
    count = 1
    do i = 1, 3
        do j = 1, 3
            do k = 1, 3
                cube(i, j, k) = count
                count = count + 1
            end do
        end do
    end do

    print *, 'Cube:'
    print *, cube
end program threeDimensionalArrayDeclaration

疑問点

「何次元までいけるの?」

利用可能なメモリ容量の範囲内で任意の次元がとれます。

「hypercube って何?」

日本語で超立方体といい、三次元空間での立方体を一般化した、高次元空間における胞体(多面体の概念を一般化したもの)のこと。

まとめ

今回は多次元配列について解説しました。内容自体は簡単で、活用の仕方が幅広く、重要なツールになりそうですね。
第6回はファイル操作です。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第4回 書式設定
→第6回 ファイル操作

書式設定 - format specification(Fortran 第4回)

←第3回 多重ループ
→第5回 多次元配列

はじめに

第4回は書式設定です。
今回はアルゴリズムの話とかではなく、どちらかというと付随的な要素なのですが、あまり聞き慣れない内容だったので解説します。

書式設定とは

書式設定とは、プログラミング言語においてデータの入力や出力の仕方を規定する設定のこと。最も代表的な例だと、数値データを何桁まで表示するか、といった設定がある。

書式設定の解説

以下の例に基づいて解説する。
書式設定はread, writeのカッコ内の2つ目の値で指定する。
I5: 5桁の整数
F10.2 10桁の浮動小数点数、そのうち2桁を小数点以下の値として表示。
なお、2I5とは I5 が2つという意味である。

program formatExample
    implicit none
    integer :: i, j
    real :: r

    ! Use a format specification to read two integers and a real number
    read(*, '(2I5,F10.2)') i, j, r

    ! Print the values using a format specification
    write(*, '(2I5,F10.2)') i, j, r
end program formatExample

おまけ

Ew.d: wは合計の桁数で、dは小数点以下の桁数。大きい値や、小さい値を勝手に指数表示にしてくれる。
Aw: wは文字列の幅を表す。
Lw: wは論理値の幅を表す。

まとめ

今回は書式設定について解説しました。書式設定は覚えるのが結構大変なので、慣れるまではその都度ググればよいでしょう。自分がよく使っている言語でも、こんな書式設定があったのかとしばしば驚かされることがあります。
第5回は多次元配列です。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第3回 多重ループ
→第5回 多次元配列

多重ループ - nested loop(Fortran 第3回)

←第2回 組み込み関数
→第4回 書式設定

はじめに

第3回は多重ループです。
多重でない単体のループに関しては解説していませんでしたが、多重ループの例を見ていただければ理解できると思います。

多重ループとは

ループの内部にほかのループを配置する構造のことで、多次元のデータに対して有効です。

多重ループの解説

ループ処理は具体例1のようにdo~end doのブロックでひとまとまりで、
i = (始め), (終わり) のように回数を指定できます。
具体例1(どのような順番でループが実行されるか表示)

program nestedLoopsExample
    implicit none
    integer :: i, j

    ! Outer loop
    do i = 1, 3
        ! Inner loop
        do j = 1, 3
            ! Print the values of i and j
            print *, 'i =', i, 'j =', j
        end do
    end do
end program nestedLoopsExample

上の例よりも現実的な例として、行列に作用する多重ループのコードを具体例2を挙げます。
具体例2(行列に作用)

program rowSumExample
    implicit none
    integer, dimension(3, 3) :: matrix
    integer, dimension(3) :: rowSums
    integer :: i, j

    ! Initialize the matrix with some values
    matrix = reshape([1, 2, 3, 4, 5, 6, 7, 8, 9], shape=[3, 3])

    ! Calculate the sum of each row using nested loops
    do i = 1, 3
        rowSums(i) = 0
        do j = 1, 3
            rowSums(i) = rowSums(i) + matrix(i, j)
        end do
    end do

    ! Print the sum of each row
    do i = 1, 3
        print *, 'Sum of row', i, '=', rowSums(i)
    end do
end program rowSumExample

この例は、まず行列を作成した後に、一次元の配列を作って、行列の各行の和を一次元の配列の要素に代入されるようループで計算するというコードです。

まとめ

多重ループはほかの言語でもよく出てくるので特に難しくはないはずです。Fortranはループ単体の書き方も非常にシンプルで書きやすいですね。
第4回は書式設定です。

←第2回 組み込み関数
→第4回 書式設定

組み込み関数 - built-in function(Fortran 第2回)

←第1回 標準入出力
→第3回 多重ループ

はじめに

第2回は組み込み関数です。
Fortranは科学分野で活躍する言語で、言語の一部として計算などを行う組み込み関数が提供されています。

組み込み関数とは

Fortranが言語の一部として提供する関数で、数学計算、論理演算、記号列処理など広い分野の演算を行う関数が用意されています。
あまりにも種類が多すぎるので、自分がよく使う関数以外は、その時その時でググればよいでしょう。

具体例

program builtin_functions
    implicit none
    real :: x = 3.14
    integer :: i = 10
    character(len=10) :: str = 'Hello'

    ! Use ABS() to get the absolute value of a number
    print *, 'Absolute value of -x: ', abs(-x)

    ! Use LOG() to compute the natural logarithm of a number
    print *, 'Natural logarithm of x: ', log(x)

    ! Use LEN() to get the length of a string
    print *, 'Length of str: ', len(str)

    ! Use TRIM() to remove leading and trailing spaces from a string
    print *, 'Trimmed str: ', trim(str)

    ! Use MAXVAL() to find the maximum value in an array
    real :: arr(3) = [1.0, 2.0, 3.0]
    print *, 'Maximum value in arr: ', maxval(arr)
end program builtin_functions

疑問点

「組み込み関数は合計何個あるの?」

追加され続けているのではっきりとした個数はわかりませんが、主要なものでも約150個です。

まとめ

今回は組み込み関数について解説しました。正直解説するまでもない内容でしたね。
第3回は多重ループです。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第1回 標準入出力
→第3回 多重ループ

標準入出力 - standard input/output(Fortran 第1回)

←第0回 変数
→第2回 組み込み関数

はじめに

第1回は標準入出力です。
自分で書いたコードの実行結果を表示したり、ユーザーの入力に基づいて処理を行う際など、あらゆる場面で使用します。

標準入出力の解説

print * はdefault formatで表示するよ、
read(*, *) num はnumにdefault formatで入力するよ、
という意味である。
具体例(入力して内容を表示する)

program stdio_example
    implicit none
    integer :: num
    character(len=20) :: message

    ! Read an integer from standard input
    print *, 'Enter an integer:'
    read(*, *) num

    ! Write the entered integer to standard output
    print *, 'The entered integer is:', num

    ! Read a string from standard input
    print *, 'Enter a message:'
    read(*, *) message

    ! Write the entered message to standard output
    print *, 'The entered message is:', trim(message)
end program stdio_example

疑問点

「何が"標準"なの?」

ソースコードや実行ファイルに依存しない標準化された処理という意味。

「どこで入力や出力ができるの?」

コンソール画面で可能です。

まとめ

今回は標準入出力について解説しました。基本的な内容は深堀りすると逆に難しくなりがちなので、そういうもんだと割り切ってどんどん使って慣れていくしかないですね。
第2回は組み込み関数です。

注意

このページは大学のFortranの授業の予習で書いています。
直観的な理解をメモしているだけなので、厳密なところでは誤りがあるかもしれません。

←第0回 変数
→第2回 組み込み関数