Fortran INTERGER*16 の最大値

Fortran の INTEGER*16 の最大値はいくつ？と思ったので調べてみた。

Integer には bit 演算が使えるので全ビットを 1にした後に、符号ビットを落とせば良さそう。

```fortran:Max_Integer.f90
      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 でコンパイル

```shell:tcsh
% gfortran Max_Integer.f90 && ./a.out
 NOT, ISHFT(-1): 170141183460469231731687303715884105727
 NOT, ISHFT(-1) +1: -170141183460469231731687303715884105728
```

<strike>なんか、書式が古いとかワーニングが出ましたが、それは無視</strike>
ほぅ、これは声に出して読みたくないですね。最大値のついでに最小値も見えました。浮動小数点には使えない方法なのは残念。
一時間ぐらいかかりましたができるもんですね。

ちなみに `INTEGER*16` の宣言は `INTEGER(kind=16)` でも良いようです。

↓コンパイルした環境は MSYS2 の gcc 8.2.0 でした

```shell:the_GNU_Compiler_Collection
% 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
```
ついでなので

```fortran:Max_Integer.f90
% 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ファイル)](https://web.kudpc.kyoto-u.ac.jp/Archives/PDF/NewsLetter/kouhou_f90_1.pdf) というのを見つけたのでテスト。

```fortran:Max_Integer.f90
      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
```
```shell:tcsh
% 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 ... 等、変数の精度に関する値を知るための関数が多数あるようです。