こんにちは。
ハロウィンはオカマバーで死ぬほどお酒を飲まされた武田です。

いつもはPerlやPHPなどのウェブアプリケーション向けの軽量言語使っているのですが、
今回は[FORTRAN]を触ってみたいと思います。

FORTRANって何?

  • 世界で最初の高級プログラム言語
  • 登場時期1957年!
  • 科学技術計算に向いた手続き型プログラミング言語
  • 昔はパンチカードでプログラムを書いていたらしいです。ロマンチック!

いやしくもプログラムでおまんま食っているのですから
最初の高級言語を触ってみてバチはあたらないでしょう!

実験環境

  • Cent OS 6.3
  • gfortran 4.4.7

インストール

まずはFORTRANを動かさないことには話が進みません。
手元のlinuxにインストールしてみましょう。

yumでパッケージを検索

[root@localhost ~]# yum search  fortran
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: ftp.tsukuba.wide.ad.jp
 * extras: ftp.tsukuba.wide.ad.jp
 * ius: mirrors.kernel.org
 * remi-safe: mirror.bebout.net
 * updates: ftp.jaist.ac.jp
======================================================== N/S Matched: fortran ========================================================
compat-libgfortran-41.i686 : Compatibility Fortran 95 runtime library version 4.1.2
compat-libgfortran-41.x86_64 : Compatibility Fortran 95 runtime library version 4.1.2
eclipse-ptp-etfw-tau-fortran.noarch : PTP External Tools Framework: TAU Fortran Enabler
gcc-gfortran.x86_64 : Fortran support
libgfortran.i686 : Fortran runtime
libgfortran.x86_64 : Fortran runtime
mingw32-gcc-gfortran.x86_64 : MinGW Windows cross-compiler for FORTRAN for the win32 target
mingw64-gcc-gfortran.x86_64 : MinGW Windows cross-compiler for FORTRAN for the win64 target
plplot-fortran-devel.i686 : Development files for using PLplot Fortran bindings
plplot-fortran-devel.x86_64 : Development files for using PLplot Fortran bindings
FoXlibf.i686 : A Fortran XML Library
(略)

歴史ある言語だけあってかなりヒットしますね。。。

ベターっぽいコンパイラ(gcc-gfortran)をいれてみます。

yum install gcc-gfortran libgfortran

(略)

Dependencies Resolved

======================================================================================================================================
 Package                              Arch                        Version                             Repository                 Size
======================================================================================================================================
Installing:
 gcc-gfortran                         x86_64                      4.4.7-17.el6                        base                      4.7 M
 libgfortran                          x86_64                      4.4.7-17.el6                        base                      268 k
Updating for dependencies:
 cpp                                  x86_64                      4.4.7-17.el6                        base                      3.7 M
 gcc                                  x86_64                      4.4.7-17.el6                        base                       10 M
 gcc-c++                              x86_64                      4.4.7-17.el6                        base                      4.7 M
 libgcc                               x86_64                      4.4.7-17.el6                        base                      103 k
 libgomp                              x86_64                      4.4.7-17.el6                        base                      134 k
 libstdc++                            x86_64                      4.4.7-17.el6                        base                      295 k
 libstdc++-devel                      x86_64                      4.4.7-17.el6                        base                      1.6 M

Transaction Summary
======================================================================================================================================
Install       2 Package(s)
Upgrade       7 Package(s)

Total download size: 26 M

(中略)

Installed:
  gcc-gfortran.x86_64 0:4.4.7-17.el6                                 libgfortran.x86_64 0:4.4.7-17.el6

Dependency Updated:
  cpp.x86_64 0:4.4.7-17.el6      gcc.x86_64 0:4.4.7-17.el6        gcc-c++.x86_64 0:4.4.7-17.el6          libgcc.x86_64 0:4.4.7-17.el6
  libgomp.x86_64 0:4.4.7-17.el6  libstdc++.x86_64 0:4.4.7-17.el6  libstdc++-devel.x86_64 0:4.4.7-17.el6

Complete!

インストールできました。

Hello, World!

まずはHello, World!しましょう

PROGRAM HELLO
    PRINT *, 'Hello, World!'
END PROGRAM
  • コメントは ! で開始
  • メインの処理は[PROGRAM]文で囲う必要があるようです。
  • アスタリスクはprint時のフォーマットを適当なものにしてねとという指示

そんでもってコンパイルを実施(hello.f90 -> hello)
gfortran -o hello hello.f90

  • 普段、コンパイルしないから新鮮です。

コンパイル後のファイルを実行

[adjust@localhost fortran]$ ./hello
 Hello, World!

きちんとプリントできてますね。

文字列は日本語にしても。。。

[adjust@localhost fortran]$ ./hello
 ハローワールド!

表示できるみたいですね。

これでFORTRANの動作環境が整いました。

Fizzbuzz

まず手始めにfizzbuzzでもしますか。

vi fizzbuzz.f90
PROGRAM fizzbuzz
  implicit none
  integer i
  do i = 1, 100
    if (mod(i, 3) == 0 .and. mod(i, 5) == 0) then
      print *, "FizzBuzz"
    else if (mod(i, 3) == 0) then
      print *, "Fizz"
    else if (mod(i, 5) == 0) then
      print *, "Buzz"
    else 
      print *, i
    end if
  end do
end PROGRAM fizzbuzz
  • [implicit none]は暗黙の型宣言の禁止。変数利用時は宣言必須となります。perlでいう[use strict]みたいなものですね
  • loopは[do]文
  • 3の倍数and5の倍数。[mod]割り算のあまりを出す。modってなんの略かしら。and条件を .and. で表現するところに驚き

それではコンパイル&実行してみましょう

[adjust@localhost fortran]$  gfortran -o fizzbuzz fizzbuzz.f90
[adjust@localhost fortran]$ ./fizzbuzz
           1
           2
 Fizz
           4
 Buzz
 Fizz
           7
           8
 Fizz
 Buzz
          11
 Fizz
          13
          14
(略)

fizzbuzzしてますね。
このレベルではまだ書き方も特殊ってわけでもないですね。。。
カッコが無いのとprintにいちいちフォーマットを渡すのが気になるくらいでしょうか?

カレンダー

本当はここでFORTRANらしい高度な計算をしたい!ところですがあいにくそういった知識がないので。。。
ちょっと昔の懐かしcgiっぽい課題なのですがカレンダーを作ってみたいと思います。
linuxのcalコマンドくらいのものを目指します。

メイン処理部

program main
   ! 変数定義
   ! date_and_timeの日、時間、タイムゾーンを”保存”させるため変数(引数でその日を指定とかではない)
   character*10 sys_time(3)
   ! date_and_timeのより細かい値。配列で以下の形で代入させる[年,月,日,UTC との時間の差,時間,分,秒,ミリ秒]
   integer*4 now(8), lastDay, day
   ! 現在時間を取得。引数で渡した変数に入れ込まれる。 call文で関数をよびだし
   call date_and_time( sys_time(1), sys_time(2), sys_time(3), now ) 
   !曜日を表示
   call printHeader(now(1), now(2))
   ! 1日の曜日合わせて空白をあける
   call offsetfirstDate(now(1), now(2))
   ! 最終日を取得
   lastDay = getLastDay( now(1), now(2) )
   ! 日を表示 1日から最終日まででループ
   do day = 1, lastDay
      write ( *, fmt = '(I3)', advance = 'no' ), day
      ! 日曜日は改行を挟む or  最終日も改行を挟む
      if ( mod( day + week( now(1), now(2), 1 ), 7 ) == 0  .or. day == lastDay )  ) then
         print *, ""
      end if
   end do 
contains

ひとまずメイン部だけで区切ります。
ここまでで気になることは。。。
* 普段触ってる軽量言語だと気にしてないのですがかなり細かく変数定義が必要なようです。
* またprint or writeで画面に描画するのですがそこでも適切にフォーマットを指定する必要があるようです。
* write ( *, fmt = '(I3)', advance = 'no' ), day
* dayの値を表示
* fmtは I3を指定。[I]が数値が入りそれは3桁と指定。値が足りない場合は空白となる
* advance=’no’で改行をさせない

続いて関数群の箇所に移ります。

! ここから関数群
! header部、当年月と曜日表示
subroutine printHeader(y, m)
    integer*4 y, m
    write ( *, fmt = '(a)', advance = 'no' ) , "      "
    write ( *, fmt = '(I4)', advance = 'no' ), y
    write ( *, fmt = '(a)', advance = 'no' ) , "年"
    write ( *, fmt = '(I2)', advance = 'no' ), m
    write ( *, fmt = '(a)', advance = 'no' ) , "月"
    print *, ""
    print *, "日 月 火 水 木 金 土"
end subroutine

! 最初に日の分だけ空白を表示
subroutine offsetfirstDate(y, m)
    integer*4 y, m, firstDateWeek
    firstDateWeek = week(y, m, 1)
    do i = 1, firstDateWeek
       write ( *, fmt = '(a)', advance = 'no' ), "   "
    end do
end subroutine

! 指定日の曜日を取得 (日=0, 月=1, 火=2)
! 曜日の割り出しにはツェラーの公式を利用 
! https://ja.wikipedia.org/wiki/%E3%83%84%E3%82%A7%E3%83%A9%E3%83%BC%E3%81%AE%E5%85%AC%E5%BC%8F
function week( y, m, d )
    integer*4 y, m, d, week
    week = mod( y + y / 4 - y / 100 + y / 400 + ( 13 * m + 8 ) / 5 + d, 7 )
end function week

! 指定月の最終日を取得
function getLastDay( y, m )
    integer*4 y, m, getLastDay
    ! 2月のみうるう年判定
    if ( m == 2 ) then
        if ( mod( y, 4 ) == 0 ) then
             getLastDay = 29
         else 
             getLastDay = 28
         end if
    ! 1, 3, 5, 7, 8, 10, 12月
    else if ( m == 1 .or. m == 3 .or. m == 5 .or. m == 7 .or. m == 8 .or. m == 10 .or. m == 12) then
       getLastDay = 31
    ! 4, 6, 9, 11月
    else
       getLastDay = 30
    end if
end function getLastDay

end program main
  • FORTRANは計算を目的にした言語のため、日時関係の機能がない。そのため普段意識しない機能を作る必要があり
    • 曜日を算出するための関数
    • 最終日取得の関数

さ、なんとかかんとか準備が整いました。
実行してみましょう!

[adjust@localhost fortran]$ ./demo2
      2016年11月
 日 月 火 水 木 金 土
        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

無事にカレンダーが表示できました!

まとめ

簡単にはではありますがFortran触ってみました。
普段つかわないような言語でウェブアプリケーションっぽいものを作るのもたまには楽しいですね。。。

参考