fortran66のブログ

fortran について書きます。

Fortran90には数値の精度に関する関数がいくつか用意されています。

TINY() 関数は正規数の最小値を返します。EPSILON() 関数は 1.0 に比べて無視できるような小さい数を返します。NEAREST() 関数は隣接する正規数を返します。

実行結果を見ると、EPSILON() が返しているのは、1.0 の+∞側の隣接する正規数との間隔のようです。1.0 から−∞方向に隣接する正規数は、+側に比べて刻みが半分になっています。これはIEEE754単精度実数の浮動小数の表し方から予期されるもっともな結果です。

0.0 近傍を見ると、0.0 の正の側の最隣接の実数は TINY() であられる数と一致しています。それの負側の隣接の数は、当然 0.0 という事になります。一方、それの正側の隣接する数(つまり 0.0 から2番目の正規数)は、1.1754944910E-38 と TINY() より小さな増分で増えています。これは浮動小数点の定義から出てくることです。

一方、最小の正規数を2のべき乗で割ってゆくと TINY(0.0) より小さな数が現れます。これは不正奇数で、アンダーフロー制御のために存在しています。単精度実数の仮数部のビット数は23ビットなので、2**24 で割った時点で完全にアンダーフローして 0.0 になります。

PROGRAM real_number
IMPLICIT NONE
INTEGER :: i
PRINT '(A)', 'SMALL REAL NUMBERS'
PRINT '(2(A, ES20.10))', 'TINY(0.0)=', TINY(0.0), ' EPSILON(0.0)=', EPSILON(0.0)
!
PRINT *
PRINT '(A)', 'REAL NUMBERS NEAR 1.0'
PRINT '(2ES20.10)', NEAREST(1.0, -1.0), NEAREST(1.0, +1.0)
!
PRINT *
PRINT '(A)', 'REAL NUMBERS NEAR 0.0'
PRINT '(A)', 'NEAREST(0.0, 1.0), NEAREST(NEAREST(0.0, 1.0), -1.0), NEAREST(NEAREST(0.0, 1.0), +1.0)'
PRINT '(3ES20.10)', NEAREST(0.0, 1.0), NEAREST(NEAREST(0.0, 1.0), -1.0), NEAREST(NEAREST(0.0, 1.0), +1.0)
PRINT *
PRINT '(A)', 'SUBNORMAL NUMBERS'
DO i = 0, 24
 PRINT '(A, I3, ES20.8)', ' i, TINY(0.0) / 2**i: ', i, TINY(0.0) / 2**i
END DO
STOP
END PROGRAM real_number