こんにちは。
ハロウィンはオカマバーで死ぬほどお酒を飲まされた武田です。
いつもは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触ってみました。
普段つかわないような言語でウェブアプリケーションっぽいものを作るのもたまには楽しいですね。。。
コメントを残す