配列 reduction
Fortran 90 で配列 reduction 関数として、sum(), product() 等が与えられましたが、Fortran 2018 規格ではユーザー定義の reduction 演算を行う reduce 汎関数が導入されました。ここで配列 reduction とは演算の結果として、配列の次元 rank が減るような演算を行う操作を指します。
引数としては、被演算配列と結合則を満たす pure な2項演算関数を取ります。reduce 汎関数と書いてみたのは、関数を引数として取って数値を返り値として返すからです。(まぁ Fortran 文法上は、関数と書いてもばちは当たらないと思います。)
なお、ここでいう結合則は数学的な形式上の結合則で、浮動小数点数では厳密にいえば実数で成り立つ様々な結合則が成り立たたないわけですが、それは気にしなくていいそうです。
最近無料化された intel fortran が Fortran 2018 に完全準拠したと嘯いているので、以下で試してみます。
実行例
一例として積の modulo 演算を取るものを以下に示します。modulo 演算は最後に一回だけ余りをとっても、途中で演算ごとに余りをとっても結果は変わらないはずですが、積の途中で overflow すると困るので積を取るごとに余りを取りたいことがあります。reduce 汎関数を使うと、これを簡潔に書けます。
ソース・プログラム
規格では pure 関数は module (大域)変数に依存しても良いです。ただし、演算中にその module 変数が書き換えられてはならない条件付きで。
module test_m implicit none real :: r = 60.0 contains pure real function f(a, b) result(res) real, intent(in) :: a, b res = mod(a * b, r) end function f end module test_m program F2018 use test_m implicit none print *, reduce([9999.,1213.,33333.], f) !Fortran 2018 print *, mod(mod(9999. * 1213., 60.0) * 3333., 60.0) print *, mod(product([9999.,1213.,33333.]), 60.0) stop 999, quiet = .true. !Fortran 2018 end program F2018
実行結果
三番目の結果が一致しないのは、単精度仮数部が overflow して下の方の桁が切り捨てられたためだと思います。 想定通りの結果が得られたのではないかと思います。
51.00000 51.00000 36.00000
Fortran 2018 with Parallel Programming (English Edition)
- 作者:Ray, Subrata
- 発売日: 2019/08/22
- メディア: Kindle版