±0.0, ±Inf, NaN
ソースプログラム
program float2
implicit none
real :: xp, xm, yp, ym, zp, zm
integer :: k
!
! +0.0, -0.0 Minus Zero
!
xp = +0.0
xm = -0.0
print *, xp, xm
print *, log(cmplx(2.0, xp)), log(cmplx(2.0, xm))
print *
!
! +Inf, -Inf
!
yp = 1.0 / xp
ym = 1.0 / xm
print *, yp, ym
print *, atan(yp), atan(ym)
print *
!
! NaN
!
zm = sqrt(-1.0)
k = transfer(zm, k)
k = iand(k, b'01111111111111111111111111111111')
zp = transfer(k, zp)
print *, zp, zm
print '(2b33.32)', zp, zm
print *
!
! +NaN, -NaN ???
!
print *, sign(1.0, zp), sign(1.0, zm)
!
end program float2
実行結果
0.0000000E+00 -0.0000000E+00
(0.6931472,0.0000000E+00) (0.6931472,-0.0000000E+00)
Infinity -Infinity
1.570796 -1.570796
NaN NaN
01111111110000000000000000000000 11111111110000000000000000000000
1.000000 -1.000000
続行するには何かキーを押してください . . .
説明
±Zero
IEEE754 の数の体系には +0.0 と -0.0 の二つのゼロがあります。これを冗長でナンセンスとみる向きもありますが、例えば多価複素関数のリーマン面のカットラインの前後を区別するなどの目的で必要だという向きもあります。ここでは複素対数関数で虚部の正負が結果に反映されるのを見ています。
±Inf(Infinity)
IEEE754 以前はゼロでの除算は、"division by zero" の割り込みによるプログラムの強制終了を引き起こしていましたが、IEEE754では数の体系の中に ±Inf が導入されおり、結果を ±Inf のいずれかとして計算は続行されれます。ここでは Arctan(+Inf) は $\pi/2$ を、Arctan(-Inf) は $-\pi/2$ を返すことを見ています。
NaN (Not A Number)
IEEE754 以前は sqrt(-1.0) のような定義域を外れた演算は、"domain error" の割り込みによるプログラムの強制終了を引き起こしていましたが、IEEE754 では NaN という要素が数の体系の中に導入されており、結果を NaN として計算が続行されます。NaN とそれ以外の数との演算はすべて NaN と定義されています。したがって一度NaN が発生するとそれ以降の結果は皆 NaN に覆われてしまいます。(なお引数を複素数で与えれば関数 sqrt は複素数(0.0,1.0)を返します。)
しかし、奇妙なことに Intel Fortran の Sign 関数を用いると、NaN の符号ビットが読み取られ、結果が普通の数になりえます。これが Intel Fortran だけの奇行なのか、Fortran の規格によるものか、IEEE754 の規格によるものか、今のところよく分かりません。
なお NaN は定義よりビット列としては一意ではなくて沢山あります。符号ビット的に正負分同数ありますが、NaN そのものには符号はありません。
Intel Fortranでの注意
IEEE754 様模型
6bits => 1bit:符号、2bits:指数部(2^0,2^1)、3bits:仮数部(1/2,1/4,1/8)
ビット表現
000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 | ||
---|---|---|---|---|---|---|---|---|---|
000 | +0.000 | +1.000 | +2.000 | +Inf | -0.000 | -1.000 | -2.000 | -Inf | |
001 | +0.125 | +1.125 | +2.250 | NaN | -0.125 | -1.125 | -2.250 | NaN | |
010 | +0.250 | +1.250 | +2.500 | NaN | -0.250 | -1.250 | -2.500 | NaN | |
011 | +0.375 | +1.375 | +2.750 | NaN | -0.375 | -1.375 | -2.750 | NaN | |
100 | +0.500 | +1.500 | +3.000 | NaN | -0.500 | -1.500 | -3.000 | NaN | |
101 | +0.625 | +1.625 | +3.250 | NaN | -0.625 | -1.625 | -3.250 | NaN | |
110 | +0.750 | +1.750 | +3.500 | NaN | -0.750 | -1.750 | -3.500 | NaN | |
111 | +0.875 | +1.875 | +3.750 | NaN | -0.875 | -1.875 | -3.750 | NaN |
対応表
| 上 位 ビ ッ ト |
----------------------------
下|+0.0 +inf |-0.0 -Inf |
位| 非 正 | 非 正 |
ビ| 正 規 N | 正 規 N |
ッ| 規 化 a | 規 化 a |
ト| 化 数 N | 化 数 N |
| 数 | 数 |
----------------------------
数直線表示
-Inf 正規化数 非正規化数 正規化数 +Inf
|-|-+-+-+-+-+-+-|+++++++|.......|.......|+++++++|-+-+-+-+-+-+-|-|
-Huge=-3.750 -2.0 -1.0 0.0 +1.0 +2.0 +Huge=+3.75