Fortran の INTEGER*16 の最大値はいくつ?と思ったので調べてみた。
Integer には bit 演算が使えるので全ビットを 1にした後に、符号ビットを落とせば良さそう。
PROGRAM Max_Integer
IMPLICIT NONE
INTEGER*16 Imax
Imax = IEOR(Imax, Imax) ! Imax = Imax xor Imax → 0
Imax = NOT(Imax) ! Imax の全ビットを立てる
Imax = ISHFT(Imax,-1) ! 右シフトして、最上位ビットを落とす
WRITE (*,*), "NOT, ISHFT(-1):", Imax
Imax = Imax +1 ! 最大であることを確認するために +1 してみる
WRITE (*,*), "NOT, ISHFT(-1) +1:", Imax
END
下のは間違ってないことを確認のため +1。
gcc の Fortran でコンパイル
% gfortran Max_Integer.f90 && ./a.out
NOT, ISHFT(-1): 170141183460469231731687303715884105727
NOT, ISHFT(-1) +1: -170141183460469231731687303715884105728
なんか、書式が古いとかワーニングが出ましたが、それは無視
ほぅ、これは声に出して読みたくないですね。最大値のついでに最小値も見えました。浮動小数点には使えない方法なのは残念。
一時間ぐらいかかりましたができるもんですね。
ちなみに INTEGER*16
の宣言は INTEGER(kind=16)
でも良いようです。
↓コンパイルした環境は MSYS2 の gcc 8.2.0 でした
% gfortran --version
GNU Fortran (Rev3, Built by MSYS2 project) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% uname -a
MINGW64_NT-10.0 H97-PRO 2.11.1(0.329/5/3) 2018-09-10 14:19 x86_64 Msys
ついでなので
% cat Max_Integer.f90
PROGRAM Max_Integer
IMPLICIT NONE
INTEGER(kind=8) Imax
Imax = IEOR(Imax, Imax) ! Imax = Imax xor Imax → 0
Imax = NOT(Imax) ! Imax の全ビットを立てる
Imax = ISHFT(Imax,-1) ! 右シフトして、最上位ビットを落とす
WRITE (*,*), "NOT, ISHFT(-1):", Imax
Imax = Imax +1 ! 最大であることを確認するために +1 してみる
WRITE (*,*), "NOT, ISHFT(-1) +1:", Imax
END
% gfortran Max_Integer.f90 && ./a.exe
Max_Integer.f90:8:17:
WRITE (*,*), "NOT, ISHFT(-1):", Imax
1
Warning: Legacy Extension: Comma before i/o item list at (1)
Max_Integer.f90:11:17:
WRITE (*,*), "NOT, ISHFT(-1) +1:", Imax
1
Warning: Legacy Extension: Comma before i/o item list at (1)
NOT, ISHFT(-1): 9223372036854775807
NOT, ISHFT(-1) +1: -9223372036854775808
豆知識:bit 演算で、ローテートというと、はみ出した bit が反対側の bit になって表れる演算のこと。シフトは、はみ出した bit は捨てて、反対側の bit が 0 になる演算のことです。
cure_honeyさんのコメントを見てなるほどー、と思い はじめての Fortran90 (PDFファイル) というのを見つけたのでテスト。
PROGRAM Max_Integer
IMPLICIT NONE
CHARACTER IFMT*12
CHARACTER EFMT*12
CHARACTER Lentest*1000
CHARACTER ExpLentest*100
INTEGER I
INTEGER(kind=1) I1
INTEGER(kind=2) I2
INTEGER(kind=4) I4
INTEGER(kind=8) I8
INTEGER(kind=16) I16
REAL R
REAL(kind=4) R4
REAL(kind=8) R8
REAL(kind=16) R16
IFMT = '(A I00)' ! 整数用の書式
EFMT = '(A G00.00)' ! 実数用の書式
PRINT "(A)", "=== Int ==="
PRINT IFMT, "KIND : ", KIND(I)
WRITE (IFMT(5:6), '(I0.2)') RANGE(I1) + 1
PRINT "(A)", "=== Int1 ==="
PRINT IFMT, "KIND :", KIND(I1)
PRINT IFMT, "HUGE :", HUGE(I1)
PRINT IFMT, "RANGE :", RANGE(I1)
PRINT IFMT, "BIT_SIZE :", BIT_SIZE(I1)
WRITE (IFMT(5:6), '(I0.2)') RANGE(I2) + 1
PRINT "(A)", "=== Int2 ==="
PRINT IFMT, "KIND :", KIND(I2)
PRINT IFMT, "HUGE :", HUGE(I2)
PRINT IFMT, "RANGE :", RANGE(I2)
PRINT IFMT, "BIT_SIZE :", BIT_SIZE(I2)
WRITE (IFMT(5:6), '(I0.2)') RANGE(I4) + 1
PRINT "(A)", "=== Int4 ==="
PRINT IFMT, "KIND :", KIND(I4)
PRINT IFMT, "HUGE :", HUGE(I4)
PRINT IFMT, "RANGE :", RANGE(I4)
PRINT IFMT, "BIT_SIZE :", BIT_SIZE(I4)
WRITE (IFMT(5:6), '(I0.2)') RANGE(I8) + 1
PRINT "(A)", "=== Int8 ==="
PRINT IFMT, "KIND :", KIND(I8)
PRINT IFMT, "HUGE :", HUGE(I8)
PRINT IFMT, "RANGE :", RANGE(I8)
PRINT IFMT, "BIT_SIZE :", BIT_SIZE(I8)
WRITE (IFMT(5:6), '(I0.2)') RANGE(I16) + 1
PRINT "(A)", "=== Int16 ==="
PRINT IFMT, "KIND :", KIND(I16)
PRINT IFMT, "HUGE :", HUGE(I16)
PRINT IFMT, "RANGE :", RANGE(I16)
PRINT IFMT, "BIT_SIZE :", BIT_SIZE(I16)
PRINT "(A)", "============="
PRINT "(A)", "=== Real ==="
WRITE (Lentest, '(G0)') HUGE(R)
WRITE (IFMT,1000) LEN_TRIM(Lentest)
PRINT IFMT, "KIND :", KIND(R)
PRINT "(A)", "=== Real4 ==="
WRITE (Lentest, '(G0)') HUGE(R4)
WRITE (ExpLentest, '(G0)') RANGE(R4)
WRITE (IFMT,1000) LEN_TRIM(Lentest)
WRITE (EFMT,2000) LEN_TRIM(Lentest) - LEN_TRIM(ExpLentest) - 4
PRINT IFMT, "KIND : ", KIND(R4)
PRINT EFMT, "HUGE : ", HUGE(R4)
PRINT EFMT, "TINY : ", TINY(R4)
PRINT "(A G0)","TINY G0 : ", TINY(R4)
PRINT IFMT, "RANGE : ", RANGE(R4)
PRINT IFMT, "PRECISION : ", PRECISION(R4)
PRINT EFMT, "EPSILON : ", EPSILON(R4)
PRINT "(A)", "=== Real8 ==="
WRITE (Lentest, '(G0)') HUGE(R8)
WRITE (ExpLentest, '(G0)') RANGE(R8)
WRITE (IFMT,1000) LEN_TRIM(Lentest)
WRITE (EFMT,2000) LEN_TRIM(Lentest) - LEN_TRIM(ExpLentest) - 4
PRINT IFMT, "KIND : ", KIND(R8)
PRINT EFMT, "HUGE : ", HUGE(R8)
PRINT EFMT, "TINY : ", TINY(R8)
PRINT IFMT, "RANGE : ", RANGE(R8)
PRINT IFMT, "PRECISION : ", PRECISION(R8)
PRINT EFMT, "EPSILON : ", EPSILON(R8)
PRINT "(A)", "=== Real16==="
WRITE (Lentest, '(G0)') HUGE(R16)
WRITE (ExpLentest, '(G0)') RANGE(R16)
WRITE (IFMT,1000) LEN_TRIM(Lentest)
WRITE (EFMT,2000) LEN_TRIM(Lentest) - LEN_TRIM(ExpLentest) - 4
PRINT IFMT, "KIND : ", KIND(R16)
PRINT EFMT, "HUGE : ", HUGE(R16)
PRINT EFMT, "TINY : ", TINY(R16)
PRINT IFMT, "RANGE : ", RANGE(R16)
PRINT IFMT, "PRECISION : ", PRECISION(R16)
PRINT EFMT, "EPSILON : ", EPSILON(R16)
! IFMT '(A I0)'
1000 FORMAT ("(A I",I0,")")
! EFMT '(A G00.00)'
2000 FORMAT ("(A G0.",I0,")")
END PROGRAM
% gfortran MAX_Int.F90 && ./a.exe
=== Int ===
KIND : 4
=== Int1 ===
KIND : 1
HUGE :127
RANGE : 2
BIT_SIZE : 8
=== Int2 ===
KIND : 2
HUGE :32767
RANGE : 4
BIT_SIZE : 16
=== Int4 ===
KIND : 4
HUGE :2147483647
RANGE : 9
BIT_SIZE : 32
=== Int8 ===
KIND : 8
HUGE :9223372036854775807
RANGE : 18
BIT_SIZE : 64
=== Int16 ===
KIND : 16
HUGE :170141183460469231731687303715884105727
RANGE : 38
BIT_SIZE : 128
=============
=== Real ===
KIND : 4
=== Real4 ===
KIND : 4
HUGE : 0.340282347E+39
TINY : 0.117549435E-37
TINY G0 : 0.117549435E-37
RANGE : 37
PRECISION : 6
EPSILON : 0.119209290E-06
=== Real8 ===
KIND : 8
HUGE : 0.17976931348623157E+309
TINY : 0.22250738585072014E-307
RANGE : 307
PRECISION : 15
EPSILON : 0.22204460492503131E-015
=== Real16===
KIND : 16
HUGE : 0.118973149535723176508575932662800702E+4933
TINY : 0.336210314311209350626267781732175260E-4931
RANGE : 4931
PRECISION : 33
EPSILON : 0.192592994438723585305597794258492732E-0033
%
それぞれの変数型で
KIND 変数を定義するときの KIND の値
HUGE 最大の値
TINY 最小の値
BIT_SIZE ビット数 (整数型のビット演算用)
RANGE 表現できる範囲が10進数で何桁か
PRECISION EPSILON の累乗部
EPSILON 1を代入した後、EPSILON より大きな値を足したときに差が出る (1 に対して切り捨てが起こらない最小値)
他にも DIGITS, MAXEXPONENT, MINEXPONENT, RADIX, NEAREST, RRSPACING ... 等、変数の精度に関する値を知るための関数が多数あるようです。