LoginSignup
2
0

More than 5 years have passed since last update.

Keep Fortran Great!

Last updated at Posted at 2019-03-25

Keep Fortran Great!

KeepFortranGreat.png

NaN と三分岐 GOTO 文

実数は全順序集合なので、任意の2数を持ってくれば、大・小・等しいの三つの関係の内必ず一つが成り立ちますが、IEEE754 の代数系には普通の数の他に ±∞ や NaN (Not a Number) があって、このうち NaN には順序が無いため、比較する2数のうちのどちらか(もしくは両方)が NaN のとき、三つの関係のどれも成り立たない状況が生じます。

上古 FORTRAN の三分岐 GOTO 文に、この NaN が来た時どうなるか見てみます。三分岐 GOTO 文では、変数が負、0.0、正のいずれかによって行き先が決定されます。

ソース・プログラム

NaN を 0.0 / 0.0 で生成します。gfortran のコンパイル時チェックを避けるため、zero = 0.0 を使っています。

参考記事:implicit_none さん
https://qiita.com/implicit_none/items/a96d5bdb1a0cf05b6f03

    program NaNtest
        implicit none
        real :: xnan, ynan, zero = 0.0
        xnan = zero / zero
        ynan = xnan
        print *, xnan, ynan
        print *, xnan == ynan, xnan /= ynan
!
        print *, xnan < ynan, xnan == ynan, xnan > ynan
!
        if (xnan) 1, 2, 3
1       print *, 1
        goto 99
2       print *, 2
        goto 99
3       print *, 3
99      continue
!
        print *, 'SIGN NaN', sign(1.0, xnan)
    end program NaNtest

実行結果

NaN は自分自身との比較でもイコールになりません。二つの NaN どうしの大小等比較を見てみるとすべて偽になっています。

三分岐 GOTO 文では三番目の正に来ています。
しかし、NaN の符号を見てみると、Intel Fortran と gfortran で結果が分かれます。Intel は正、gfortran は負になっています。gfortran の場合、三分岐 goto の場合と矛盾しています。まぁそもそも本来 NaN には符号が無いはずなので、意味が無いんですがw

intel fortran

            NaN            NaN
 F
 F T
 F F F
           3
 SIGN NaN   1.000000

gfortran

              NaN              NaN
 F
 F T
 F F F
           3
 SIGN NaN  -1.00000000  

弁明

一度 NaN が出ると、それ以降の計算は全部 NaN になりそうな気がしますが、sign 関数で符号を見ると普通の数に戻ってくるという事実があって、長年謎に思っていたのですが、三分岐 GOTO 文などと整合させるためではないかと思って、そういう結論を導こうとしていたのですが、gfortran の結果で主張が崩れてしまいましたw

NaN の二進内部表現の符号ビットを見ると、NaN の内部表現は一意ではないので、正の場合も負の場合も可能なのですが、Intel Fortran で調べた限りでは、符号ビットの内容に関わらず sign 関数では常に正扱いになっていました。それで上記のストーリーを考えたのですが、gfortran で思いっきり矛盾してしまいましたw

gfortran での NaN の内部表現と sign 関数の関係はまだ調べていないので、追って調べてみたいと思います。KEEP FORTRAN GREAT!

補足

ソース・プログラム

NaN をビット列で生成して、符号ビットを変えたうえで、sign 関数に入れてみます。

program hello
   real :: xnan
   xnan = transfer(B'01111111100000000000000000000001', xnan)
   print *, xnan
   print *, sign(1.0, xnan)
!
   xnan = transfer(B'11111111100000000000000000000001', xnan)
   print *, xnan
   print *, sign(1.0, xnan)
end program hello

gfortran での実行結果

gfortran では、NaN の符号ビットの逆の符号になっているようです。

              NaN
   1.00000000    
              NaN
  -1.00000000    

補足 H31.4.10
gfortran の三分岐は NaN の符号ビットに依らずに、正に相当する三番目に飛んでいます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0