“Fortran, the greatest of the programming languages!”
www.youtube.com
このような紹介記事がありました。入門としてのクオリティーは・・・お、おぅ...
Be Curious and Learn: Modern Fortran in a Nutshell | InfoWorld
“Fortran, the greatest of the programming languages!”
www.youtube.com
このような紹介記事がありました。入門としてのクオリティーは・・・お、おぅ...
Be Curious and Learn: Modern Fortran in a Nutshell | InfoWorld
HPC wire に PGAS (Partitioned Global Address Space) がそろそろ来るという記事がありました。Fortran 2008 で導入された coarray Fortran が PGAS 言語の一つとして出てきています。
PGASの定義は、以下の要に与えられています。
PGAS defined
PGAS programming models offer a partitioned global shared memory capability, via a programming language or API, whether special support exists in hardware or not.
来そうな理由として以下のものが挙げられています。
Factor 1: Hardware support for more and more cores connected coherently. Factor 2: Low latency interconnects. Factor 3: Software support growing.
日立製作所はメインフレームのハードウエア開発から撤退すると発表した。今後は米IBMから供給を受ける。IBM製のハードに日立のメインフレーム向け基本ソフト(OS)を搭載したメインフレーム製品の提供を2018年度内に始める。
メインフレームはメガバンクや企業、行政機関などの基幹業務システムに広く採用されていたが、近年はパソコンサーバーによるオープンシステムの台頭により市場規模が縮小している。1990年代半ばに1兆円規模だったメインフレームの国内出荷金額は15年度には400億円前後まで落ち込んでいる。
日立は事業の選択と集中に向けて、ハード開発からの撤退を決めた。ただ既存システムの安定稼働を重視する企業を中心にメインフレームの需要は根強い。既存システムのソフトウエア資産の活用を支援するため、メインフレーム向けOSやミドルウエアソフトの開発は今後も継続する。
メインフレームの国内出荷金額は15年度には400億円前後まで落ち込んでいる。
IEEE754 の規格では、加減乗除の二項演算について、実数とその浮動小数点数表現の構造が保たれることを要求しています。つまり、加算の場合を例にとると、
a + b = c fl(a) + fl(b)= fl(a + b) = fl(c)
この性質があるので、実数の可換な性質は保たれます。(overflow とかしなければ)
fl(a) + fl(b)= fl(a + b) = fl(b + a) = fl(b) + fl(a)
一方、実数で成り立つもっと基本的な演算規則である結合則の方は、三項演算に相当していて、規格からの要請もなく(たぶんw)成り立たない場合があります。「桁落ち」や「積み残し」が問題化するのは結合則からのズレに還元できると思います。結合則が成り立たない場合、演算の順序を明示的に指示する必要が出てきます。
(a + b) + c = a + (b + c) (fl(a) + fl(b)) + fl(c) = fl(a + b) + fl(c) /= fl(a) + (fl(b) + fl(c)) = fl(a) + fl(b + c)
プログラムで、見てみることにしてみます。
乱数で実数を生成して、交換子と結合子を計算してして、交換則と結合則からのずれを見てみます。ズレがなければ 0.0 になるはずです。
program Console1 implicit none integer, parameter :: kd = kind(1.0d0), nmax = 100 real(kd) :: x(2, nmax), y(3, nmax), z(nmax) integer :: i call random_seed() print *, 'commutator' call random_number(x) z = comm_plus(x(1, :), x(2, :)) print *, 'non-commutative =', count(z /= 0.0_kd), '/', nmax print *, 'associator' call random_number(y) z = assoc_plus(y(1, :), y(2, :), y(3, :)) print *, 'non-associative =', count(z /= 0.0_kd), '/', nmax print '(e30.15)', pack(z, z /= 0.0_kd) do i = 1, nmax if (z(i) /= 0.0_kd) print *, y(:, i) end do contains real(kd) pure elemental function comm_plus(x, y) real(kd), intent(in) :: x, y comm_plus = (x + y) - (y + x) end function comm_plus real(kd) pure elemental function comm_mult(x, y) real(kd), intent(in) :: x, y comm_mult = (x * y) - (y * x) end function comm_mult real(kd) pure elemental function assoc_plus(x, y, z) real(kd), intent(in) :: x, y, z assoc_plus = ((x + y) + z) - (x + (y + z)) end function assoc_plus real(kd) pure elemental function assoc_mult(x, y, z) real(kd), intent(in) :: x, y, z assoc_mult = ((x * y) * z) - (x * (y * z)) end function assoc_mult end program Console1
計算結果から分かるように、交換則の方は確かに満たされていますが、結合則の方は2割程度の確率で満たされていないことが分かります。
ステパノフの本や関数型言語の本などでは、結合則を根底において、モノイド、半群、群などの造を導入して、結合則による演算順序の組み換えを縦横に使って並列動作などさせていますが、整数や文字列のような離散値の場合はよいとして、浮動小数点数の場合は結合則が崩れているので、実数の演算の問題にどこまで適用できるのか慎重に見極める必要がある気がします。
commutator non-commutative = 0 / 100 associator non-associative = 22 / 100 -0.222044604925031E-15 0.222044604925031E-15 -0.444089209850063E-15 0.222044604925031E-15 0.222044604925031E-15 0.222044604925031E-15 -0.222044604925031E-15 0.222044604925031E-15 0.222044604925031E-15 0.222044604925031E-15 -0.444089209850063E-15 -0.222044604925031E-15 0.222044604925031E-15 -0.222044604925031E-15 0.111022302462516E-15 0.444089209850063E-15 0.111022302462516E-15 0.111022302462516E-15 0.222044604925031E-15 0.222044604925031E-15 0.222044604925031E-15 0.444089209850063E-15 0.197336647554121 0.583104599529825 0.230515619550751 0.478456421601024 0.365995662803589 0.695310195955152 0.765030199209025 0.821438970892834 0.822794756357349 0.154500948792594 0.776532299353388 0.343291349327081 0.123168650301795 0.892064457677992 0.624841959267652 5.340595195978214E-002 0.883762457929461 0.282097598062034 0.271274877739308 0.990276136982007 0.295042576304925 0.385678503561146 0.550016479450929 0.368699724012741 0.649285046006193 0.772531681072521 0.291322963201651 6.278512502868444E-002 0.484351337035122 0.846490729577704 0.791263186492663 0.730073920942973 0.590455112135355 0.599791134233700 0.716285730192570 0.379474641874127 0.271981838214423 0.686661556999306 0.655546444804149 9.427993838386348E-002 0.387223376386792 0.590407433074261 0.295995343550855 0.100678724962143 0.578481472642591 0.631307369405927 0.834670683810024 0.762999289601546 0.634957778719910 0.129886627681722 0.170474343695826 0.131887838808105 6.074681699437982E-002 0.581256123449080 8.217122777577210E-002 0.437050020391703 0.846554402242005 0.522359744366527 0.748392434610684 0.567776991641634 0.555136565205923 0.518809881107340 0.750619304274506 0.487565338352254 0.577165852794002 0.970361542180519 続行するには何かキーを押してください . . .
Fortran では、意外にも定義の先取りができることがままあって、知らないと損します。再帰的な構造体の定義などが典型的なものですが、その他にも微妙なところで気が利いていたりします。
program test1 implicit none integer :: i, n real :: a(3, 2) = reshape([(real(i), i = 1, 6)], shape(a)) ! <-- shape(a) real :: b(6) print '(2g10.2)', transpose(a) end program test1
実数配列を宣言しますが、その初期化時に右辺で定義する配列の形状・サイズ等 a の属性を利用できます。
実行結果
1.0 4.0 2.0 5.0 3.0 6.0 続行するには何かキーを押してください . . .
program test2 implicit none integer :: i, n real :: a(3, 2) = reshape([(real(i), i = 1, 6)], shape(a)) real :: b(6) ! write(9) size(a), a close(9) read(9) n, (b(i), i = 1, n) ! <-- n print *, b end program test2
ファイルからデータを読み込むときに、読み取ったデータが同一行での implied do loop の中で利用できます。これは、実行時の変数の値の確定順序によるもので、ちょっと見には値不定のような気がしますが、Fortran では規格で許されている利用法です。
実行結果
1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 続行するには何かキーを押してください . . .
他にも色々あると思いますが、すぐには出てこない・・・