🍒
JuliaとFortranのmodが違う話
昔, 言語によってmodの(特に負の引数での)挙動が違って苦労した経験があり, プログラムを他言語に移植する際は必ずチェックするようにしています. JuliaとFortran(gfortran)では同じ挙動だったのでメモしておきます. 寝ぼけてたのか? やはり負の引数での挙動が違うので, 移植方法をまとめます.
Juliaのmod
JuliaのmodはFortranのmodと違うので注意しましょう.
versioninfo()
Julia Version 1.7.1
Commit ac5cc99908 (2021-12-22 19:35 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-12.0.1 (ORCJIT, haswell)
プログラム
for i in -6:6
println(i, "\t", mod(i,3))
end
出力
-6 0
-5 1
-4 2
-3 0
-2 1
-1 2
0 0
1 1
2 2
3 0
4 1
5 2
6 0
Juliaのrem
JuliaのremはFortranのmodに相当します.
rem
for i in -6:6
println(i, "\t", rem(i,3))
end
出力
-6 0
-5 -2
-4 -1
-3 0
-2 -2
-1 -1
0 0
1 1
2 2
3 0
4 1
5 2
6 0
Fortran
見ての通り, Juliaのmod(i,3)
とは負の引数での挙動が違います. Fortranのmod(i,3)
はJuliaのrem(i,3)
と同じです.
gfortran -v
Using built-in specs.
COLLECT_GCC=C:\mingw-w64\mingw64\bin\gfortran.exe
COLLECT_LTO_WRAPPER=C:/mingw-w64/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
プログラム
program main
implicit none
integer :: i
do i = -6,6
print *, i, mod(i,3)
end do
end program main
出力
-6 0
-5 -2
-4 -1
-3 0
-2 -2
-1 -1
0 0
1 1
2 2
3 0
4 1
5 2
6 0
FortranからJuliaへの移植
古いFortranのコードをJuliaに書き直すことが多いと思いますので, 負の値の挙動について気を付けましょう. if文を使うと場所を取るので, 三項演算子で負の値を判定しています. Fortranのmod(i,3)
をJuliaではi<0 ? -mod(-i,3) : mod(i,3)
またはrem(i,3)
のように書き換えます. 簡単なので単にrem(i,3)
を用いることを推奨します.
Fortranと同じ出力を得るコード
for i in -6:6
println(i, "\t", i<0 ? -mod(-i,3) : mod(i,3))
end
出力
-6 0
-5 -2
-4 -1
-3 0
-2 -2
-1 -1
0 0
1 1
2 2
3 0
4 1
5 2
6 0
JuliaからFortranへの移植
並列計算とかスパコンでの利用のためにJuliaのコードをFortranに書き直すことがたまにあるので, 一応書いておきます. Juliaのmod(i,3)
をFortranではmod(abs(i+3),3)
とします. 正の引数では変化せず, 負の引数のみ変化します.
Juliaと同じ出力を得るコード
program main
implicit none
integer :: i
do i = -6,6
print *, i, mod(abs(i+3),3)
end do
end program main
出力
-6 0
-5 2
-4 1
-3 0
-2 1
-1 2
0 0
1 1
2 2
3 0
4 1
5 2
6 0
ソースコード
Gistにファイルとして置いておきます.
Discussion