6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FortranAdvent Calendar 2023

Day 24

Fortranのビット演算・ビット操作

Last updated at Posted at 2023-12-23

概要

Fortranが標準で備えているビット演算やビット操作,比較,変換などをまとめました.
本記事で紹介している機能一覧は下記の通りです.

環境

  • Windows 10 64 bit
  • Windows 11 64 bit
  • gfortran 10.3, 11.2
  • Intel Fortran classic 2021.5.0
  • NAG Fortran 7.1.0

Fortran 2023での拡張

本記事はFortran 2018規格に沿って記述していますが,Fortran 20203において,2進(および8進,16進)定数の取り扱いが拡張されることになりました.
本記事に関係するところでは,2進定数そのままでは代入演算子の右辺とすることができなかったのが,下記の場合にそのまま右辺とすることができるようになりました.

  • 整数あるいは実数の名前付きオブジェクトの初期化
  • 整数あるいは実数への組み込み代入演算
  • 整数あるいは実数の配列構成子内
  • enumの整数値

表示

ビットに着目するからには,変数を2進数で表示できる必要があります.Fortranでは変数を2進数で表示することも,2進数で表現した数値リテラルを変数に代入することもできます.

数値リテラルとして取り扱う場合は,基数を表す記号の後ろに数値を文字列として記述します.

基数 基数を表す記号 表記例
2 B B'1111100111'

2進数表記では,それが表す数値の型が不明なので,型変換用の関数と併用する必要があります.

! これは許可されない
! print '(I4)', B'1111100111'

print *,  int(B'1111100111') ! 999
print *, real(B'1111100111') ! 1.3998972E-42

変数に2進数リテラルを代入する場合も同様です.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i
    real(real32) :: r

    ! これは許可されないが,Fortran 2023からは許可される
    ! i = B'1111100111'
    ! r = B'1111100111'

    i = int(B'1111100111')
    r = real(B'1111100111')
    print *, i, r ! 999  1.3998972E-42
end program main

2進数で表示する場合には,print文もしくはwrite文の書式で指定します.上位ビットが0の場合は表示が省略されます.その場合は,書式指定で.の後ろに表示する桁数を記述します.

基数 書式例 記述例 表示結果
2 '(B8)' print '(B8)', 100_int8 1100100
2 '(B8.8)' print '(B8.8)', 100_int8 01100100

ここでは2進数についてのみ述べましたが,8進数,16進数も同様に取り扱う事ができます.基数を表す記号は,8進数の場合はO,16進数の場合はZで,2, 8, 16進数をまとめてBOZリテラルとよばれます.

基数 基数を表す記号 表記例
2 B B'1111100111'
8 O O'12345670'
16 Z Z'A1B2'

演算

ここでは,2項もしくは単項演算を行う手続を紹介します.

iand

二つの整数型変数,整数リテラル,あるいはBOZリテラルのビットごとの論理積を計算し,結果を整数で返します.

書式

  • result = iand(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは整数.
      • iが整数ならiと同じkind,そうでなければjと同じkind.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

結果の値は,ビットごとに下記の真理値表に従って計算されます.

i j iand(i,j)
0 0 0
1 0 0
0 1 0
1 1 1

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j

    i = int(B'10101010', kind=int8)
    j = int(B'01010101', kind=int8)
    print '(B8.8)', iand(i, j) ! 00000000
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'1111')
    j = int(B'1111')
    print '(B32.32)', iand(i, j) ! 00000000000000000000000000001111
end program main
program main
    implicit none

    print '(B32.32)', iand(    B'11110000000000000000000000000000', &
                           int(B'11110000000000000000000000000000'))
    ! 11110000000000000000000000000000
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: i(:), j(:)

    i = [integer(int8) :: 125, 126, 127]
    j = [integer(int8) :: 15, 15, 15]
    print '(*(B8.8:," "))', i          ! 01111101 01111110 01111111
    print '(*(B8.8:," "))', j          ! 00001111 00001111 00001111
    print '(*(B8.8:," "))', iand(i, j) ! 00001101 00001110 00001111
end program main

ior

二つの整数型変数,整数リテラル,あるいはBOZリテラルのビットごとの包含的論理和(1と1の論理和が1)を計算し,結果を整数で返します.

書式

  • result = ior(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは整数.
      • iが整数ならiと同じkind,そうでなければjと同じkind.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

結果の値は,ビットごとに下記の真理値表に従って計算されます.

i j ior(i,j)
0 0 0
1 0 1
0 1 1
1 1 1

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j

    i = int(B'10101011', kind=int8)
    j = int(B'01010101', kind=int8)
    print '(B8.8)', ior(i, j) ! 11111111
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i

    i = int(B'1010')
    print '(B32.32)', ior(i, B'1101') ! 00000000000000000000000000001111
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: i(:), j(:)

    i = [integer(int8) :: 125, 126, 127]
    j = [integer(int8) :: 15, 15, 15]
    print '(*(B8.8:," "))', i         ! 01111101 01111110 01111111
    print '(*(B8.8:," "))', j         ! 00001111 00001111 00001111
    print '(*(B8.8:," "))', ior(i, j) ! 01111111 01111111 01111111
end program main

ieor

二つの整数型変数,整数リテラル,あるいはBOZリテラルのビットごとの排他的論理和(1と1の論理和が0)を計算し,結果を整数で返します.

書式

  • result = ieor(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは整数.
      • iが整数ならiと同じkind,そうでなければjと同じkind.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

結果の値は,ビットごとに下記の真理値表に従って計算されます.

i j ieor(i,j)
0 0 0
1 0 1
0 1 1
1 1 0

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j

    i = int(B'10101011', kind=int8)
    j = int(B'01010101', kind=int8)
    print '(B8.8)', ieor(i, j) ! 11111110
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i

    i = int(B'1010')
    print '(B32.32)', ieor(i, B'1101') ! 00000000000000000000000000000111
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: i(:), j(:)

    i = [integer(int8) :: 125, 126, 127]
    j = [integer(int8) :: 15, 15, 15]
    print '(*(B8.8:," "))', i          ! 01111101 01111110 01111111
    print '(*(B8.8:," "))', j          ! 00001111 00001111 00001111
    print '(*(B8.8:," "))', ieor(i, j) ! 01110010 01110001 01110000
end program main

not

整数型変数,整数リテラルの論理否定を計算し,結果を整数で返します.

書式

  • result = not(i)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • resultは整数.
      • iと同じkind.
      • iが配列の場合,resultiと同じ次元,要素数の配列.

結果の値は,ビットごとに下記の真理値表に従って計算されます.

i not(i)
0 1
1 0

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'10101010', kind=int8)
    print '(B8.8)', not(i) ! 01010101
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: i(:)

    i = [integer(int8) :: 2, 4, 8]
    print '(*(B8.8:," "))', i      ! 00000010 00000100 00001000
    print '(*(B8.8:," "))', not(i) ! 11111101 11111011 11110111
end program main

iall

整数型配列を構成する全要素について,ビットごとの論理積を計算し,結果を整数型配列で返します.
簡単に,全要素のiand,あるいは次元ごとのiandを計算すると考えてもらっても問題ありません.

書式

  • result = iall(array [, dim] [, mask])
    • arrayは整数(1, 2, 4, 8バイト)型配列.
    • dimは整数で,1以上arrayの配列次元数以下の値.
      • 省略された場合,arrayを1次元配列として処理する.
    • maskは論理型で,arrayと同じ形状の配列.
    • resultは整数型配列あるいはスカラ.
      • kindはarrayと同じ.
      • 配列次元は,arrayの次元-1.
      • arrayが1次元あるいはdimが省略された場合はスカラ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:)

    a = [integer(int8) :: int(B'1110'), int(B'1101'), int(B'1011')]

    print '(*(B4.4:, " "))', a ! 1110 1101 1011
    print '(*(B4.4:, " "))', iall(a) ! 1000
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:)

    a = [integer(int8) :: int(B'1110'), int(B'1101'), int(B'1011')]

    print '(*(B4.4:, " "))', a ! 1110 1101 1011
    print '(*(B4.4:, " "))', iall(a, mask=[.true., .false., .true.]) ! 1010
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01111011'), int(B'01111110'), int(B'01111101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01111011 01111110 01111101
    print '(*(B8.8:, " "))', iall(a) ! 00001000
    ! 全要素のiandを計算
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01111011'), int(B'01111110'), int(B'01111101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01111011 01111110 01111101
    print '(*(B8.8:, " "))', iall(a, dim=1) ! 00001000 01111000
    ! iandを→方向に計算 int(B'00001110'), int(B'00001101'), int(B'00001011')
    ! iandを→方向に計算 int(B'01111011'), int(B'01111110'), int(B'01111101')
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01111011'), int(B'01111110'), int(B'01111101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01111011 01111110 01111101
    print '(*(B8.8:, " "))', iall(a, dim=2) ! 00001010 00001100 00001001
    ! iandを↓方向に計算  iandを↓方向に計算  iandを↓方向に計算
    ! int(B'00001110'), int(B'00001101'), int(B'00001011')
    ! int(B'01111011'), int(B'01111110'), int(B'01111101')
end program main

iany

整数型配列を構成する全要素について,ビットごとの包含的論理和を計算し,結果を整数型配列で返します.
簡単に,全要素のior,あるいは次元ごとのiorを計算すると考えてもらっても問題ありません.

書式

  • result = iany(array [, dim] [, mask])
    • arrayは整数(1, 2, 4, 8バイト)型配列.
    • dimは整数で,1以上arrayの配列次元数以下の値.
      • 省略された場合,arrayを1次元配列として処理する.
    • maskは論理型で,arrayと同じ形状の配列.
    • resultは整数型配列あるいはスカラ.
      • kindはarrayと同じ.
      • 配列次元数は,arrayの次元-1.
      • arrayが1次元あるいはdimが省略された場合はスカラ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32), allocatable :: a(:)

    a = [int(B'1001'), int(B'0101'), int(B'0011')]

    print '(*(B4.4:, " "))', a ! 1001 0101 0011
    print '(*(B4.4:, " "))', iany(a) ! 1111
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32), allocatable :: a(:)

    a = [int(B'1001'), int(B'0101'), int(B'0011')]

    print '(*(B4.4:, " "))', a ! 1001 0101 0011
    print '(*(B4.4))', iany(a, mask=[.true., .false., .true.]) ! 1011
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iany(a) ! 01111111
    ! 全要素のiorを計算
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iany(a, dim=1) ! 00001111 01111111
    ! ianyを→方向に計算 int(B'00001110'), int(B'00001101'), int(B'00001011')
    ! ianyを→方向に計算 int(B'01001011'), int(B'00011110'), int(B'00101101')
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iany(a, dim=2) ! 01001111 00011111 00101111
    ! ianyを↓方向に計算  ianyを↓方向に計算  ianyを↓方向に計算
    ! int(B'00001110'), int(B'00001101'), int(B'00001011')
    ! int(B'01001011'), int(B'00011110'), int(B'00101101')
end program main

iparity

整数型配列を構成する全要素について,ビットごとの排他的論理和を計算し,結果を整数型配列で返します.
簡単に,全要素のieor,あるいは次元ごとのieorを計算すると考えてもらっても問題ありません.

書式

  • result = iparity(array [, dim] [, mask])
    • arrayは整数(1, 2, 4, 8バイト)型配列.
    • dimは整数で,1以上arrayの配列次元数以下の値.
      • 省略された場合,arrayを1次元配列として処理する.
    • maskは論理型で,arrayと同じ形状の配列.
    • resultは整数型配列あるいはスカラ.
      • kindはarrayと同じ.
      • 配列次元数は,arrayの次元-1.
      • arrayが1次元あるいはdimが省略された場合はスカラ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32), allocatable :: a(:)

    a = [int(B'1001'), int(B'0101'), int(B'0011')]

    print '(*(B4.4:, " "))', a ! 1001 0101 0011
    print '(*(B4.4))', iparity(a) ! 1111
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32), allocatable :: a(:)

    a = [int(B'1001'), int(B'0101'), int(B'0011')]

    print '(*(B4.4:, " "))', a ! 1001 0101 0011
    print '(*(B4.4))', iparity(a, mask=[.true., .false., .true.]) ! 1010
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iparity(a) ! 01110000
    ! 全要素のieorを計算
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iparity(a, dim=1) ! 00001000 01111000
    ! iparityを→方向に計算 int(B'00001110'), int(B'00001101'), int(B'00001011')
    ! iparityを→方向に計算 int(B'01001011'), int(B'00011110'), int(B'00101101')
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8), allocatable :: a(:, :)

    a = reshape([integer(int8) :: &
                 int(B'00001110'), int(B'00001101'), int(B'00001011'), &
                 int(B'01001011'), int(B'00011110'), int(B'00101101')], &
                [3, 2])

    print '(*(B8.8:, " "))', a ! 00001110 00001101 00001011 01001011 00011110 00101101
    print '(*(B8.8:, " "))', iparity(a, dim=2) ! 01000101 00010011 00100110
    ! iparityを↓方向に計算  iparityを↓方向に計算  iparityを↓方向に計算
    ! int(B'00001110'),    int(B'00001101'),    int(B'00001011')
    ! int(B'01001011'),    int(B'00011110'),    int(B'00101101')
end program main

parity

論理型配列を構成する全要素の.neqv.,あるいは次元ごとの.neqv.を計算した結果を論理値で返します.
簡単に,論理型配列内の真の要素が奇数個の場合に真,偶数個の場合に偽を返すと考えてもらっても問題ありません.

書式

  • result = parity(array [, dim])
    • arrayは論理型配列.
    • dimは整数で,1以上arrayの配列次元数以下の値.
      • 省略された場合,arrayを1次元配列として処理する.
    • resultは論理型配列あるいはスカラ.
      • 配列次元数は,arrayの次元-1.
      • arrayが1次元あるいはdimが省略された場合はスカラ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    logical, allocatable :: a(:)

    a = [.true., .false., .true.]

    print '(*(L1:, " "))', a ! T F T
    print '(*(L1:, " "))', parity(a) ! F
end program main

``Fortran
program main
use, intrinsic :: iso_fortran_env
implicit none
logical, allocatable :: a(:)

a = [.true., .false., .true.]

print '(*(L1:, " "))', a ! F T F
print '(*(L1:, " "))', parity(a) ! T

end program main


``Fortran
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    logical, allocatable :: a(:, :)

    a = reshape([.true., .false., .true., &
                 .false., .true., .false.], &
                [3, 2])

    print '(*(L1:, " "))', a ! T F T F T F
    print '(*(L1:, " "))', parity(a) ! T
end program main

``Fortran
program main
use, intrinsic :: iso_fortran_env
implicit none
logical, allocatable :: a(:, :)

a = reshape([.true., .false., .true., &
             .false., .true., .false.], &
            [3, 2])

print '(*(L1:, " "))', a ! T F T F T F
print '(*(L1:, " "))', parity(a, dim=1) ! F T

end program main


``Fortran
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    logical, allocatable :: a(:, :)

    a = reshape([.true., .false., .true., &
                 .false., .true., .false.], &
                [3, 2])

    print '(*(L1:, " "))', a ! T F T F T F
    print '(*(L1:, " "))', parity(a, dim=2) ! T T T
end program main

シフト

ここでは,ビットシフトを行う手続を紹介します.

ishft

整数型変数あるいは整数リテラルを,右あるいは左方向に指定の桁だけビットシフトした値を整数で返します.左端あるいは右端からはみ出したビットは破棄され,反対側には0が設定されます.

書式

  • result = ishft(i, shift)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • shiftは整数で,その絶対値は1以上iのビットサイズ以下の値.
      • shift>0の場合,左方向にシフトが行われる.
      • shift<0の場合,右方向にシフトが行われる.
      • 0の場合,シフトは行われない.
      • shiftは配列でもよい.
      • ishiftの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • shiftが配列の場合,resultshiftと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11100111', kind=int8)
    print '(*(B8.8:, " "))', ishft(i, 2)  ! 10011100
    print '(*(B8.8:, " "))', ishft(i, 0)  ! 11100111
    print '(*(B8.8:, " "))', ishft(i, -2) ! 00111001
end program main

ishftc

整数型変数あるいは整数リテラルを,右あるいは左方向に指定の桁だけビットシフトした値を返します.ビットシフトは循環的に行われ,左端あるいは右端からはみ出したビットは反対側に設定されます.

書式

  • result = ishftc(i, shift)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • shiftは整数で,その絶対値は1以上iのビットサイズ以下の値.
      • shift>0の場合,左方向に循環シフトが行われる.
      • shift<0の場合,右方向に循環シフトが行われる.
      • 0の場合,シフトは行われない.
      • shiftは配列でもよい.
      • ishiftの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11100111', kind=int8)
    print '(*(B8.8:, " "))', ishftc(i, 2)  ! 10011111
    print '(*(B8.8:, " "))', ishftc(i, 0)  ! 11100111
    print '(*(B8.8:, " "))', ishftc(i, -2) ! 11111001
end program main

shifta

整数型変数あるいは整数リテラルを,指定の桁だけ右方向にビットシフトした値を返します.左端からはみ出したビットは破棄され,右のシフトされたビット分には,シフトされる整数の最上位ビットの値が詰められます.

書式

  • result = shifta(i, shift)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • shiftは整数で,1以上iのビットサイズ以下の値.
      • 0の場合,シフトは行われない.
      • shiftは配列でもよい.
      • ishiftの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • shiftが配列の場合,resultshiftと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'10000000', kind=int8)
    print '(*(B8.8:, " "))', shifta(i, 2) ! 11100000
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'01111111', kind=int8)
    print '(*(B8.8:, " "))', shifta(i, 2) ! 00011111
end program main

shiftl

整数型変数あるいは整数リテラルを,指定の桁だけ左方向にビットシフトした値を返します.左端からはみ出したビットは破棄され,右側には0が詰められます.

書式

  • result = shiftl(i, shift)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • shiftは整数で,1以上iのビットサイズ以下の値.
      • 0の場合,シフトは行われない.
      • shiftは配列でもよい.
      • ishiftの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • shiftが配列の場合,resultshiftと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11111111', kind=int8)
    print '(*(B8.8:, " "))', shiftl(i, 2) ! 11111100
end program main

shiftr

整数型変数あるいは整数リテラルを,指定の桁だけ右方向にビットシフトした値を返します.右端からはみ出したビットは破棄され,左側には0が詰められます.

書式

  • result = shiftl(i, shift)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • shiftは整数で,1以上iのビットサイズ以下の値.
      • 0の場合,シフトは行われない.
      • shiftは配列でもよい.
      • ishiftの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • shiftが配列の場合,resultshiftと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11111111', kind=int8)
    print '(*(B8.8:, " "))', shiftr(i, 2) ! 00111111
end program main

比較

ここでは,ビット単位の比較を行う組み込み手続を紹介します.

bge

二つの整数型変数,整数リテラルあるいはBOZリテラルをビットごとに比較し,ビット列が大きいか等しいかを判別した結果を論理値で返します.この比較において,最上位ビットは符号ビットとは解釈されません.

書式

  • result = bge(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは論理型.
      • iのビット列がjのビット列より大きいか等しい場合に真,そうでない場合に偽となる.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111110')
    print *, bge(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111111')
    print *, bge(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'00000000000000000000000000000000')
    j = int(B'11111111111111111111111111111111')
    print *, bge(i, j) ! F
end program main

bgt

二つの整数型変数,整数リテラルあるいはBOZリテラルをビットごとに比較し,ビット列が大きいかを判別した結果を論理値で返します.この比較において,最上位ビットは符号ビットとして解釈されません.

書式

  • result = bgt(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは論理型.
      • iのビット列がjのビット列より大きい場合に真,そうでない場合に偽となる.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111110')
    print *, bgt(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111111')
    print *, bgt(i, j) ! F
end program main

ble

二つの整数型変数,整数リテラルあるいはBOZリテラルをビットごとに比較し,ビット列が小さいか等しいかを判別します.この比較において,最上位ビットは符号ビットとして解釈されません.

書式

  • result = ble(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは論理型.
      • iのビット列がjのビット列より小さいか等しい場合に真,そうでない場合に偽となる.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111110')
    j = int(B'01111111111111111111111111111111')
    print *, ble(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111111')
    print *, ble(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'00000000000000000000000000000000')
    j = int(B'11111111111111111111111111111111')
    print *, ble(i, j) ! T
end program main

blt

二つの整数型変数,整数リテラルあるいはBOZリテラルをビットごとに比較し,ビット列が小さいかを判別した結果を論理値で返します.この比較において,最上位ビットは符号ビットとして解釈されません.

書式

  • result = ble(i, j)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
      • i, jは配列でもよい.
    • resultは論理型.
      • iのビット列がjのビット列より小さい場合に真,そうでない場合に偽となる.
      • i, jが配列の場合,resulti, jと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111110')
    j = int(B'01111111111111111111111111111111')
    print *, blt(i, j) ! T
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i, j

    i = int(B'01111111111111111111111111111111')
    j = int(B'01111111111111111111111111111111')
    print *, blt(i, j) ! F
end program main

変換・操作

整数をビット単位で操作する手続や,ビット列を他の表現として解釈するような手続を紹介します.
これらの手続きでビットの位置を指定する場合,最下位ビットの位置を0とします.

ibset

整数型変数あるいは整数リテラルの,指定された位置のビットを1に置き換えた値を整数で返します.

書式

  • result = ibset(i, pos)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • posは整数で,0以上iのビットサイズ未満の値.
      • posは配列でもよい.
      • iposの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • posが配列の場合,resultposと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'00000000', kind=int8)
    print '(*(B8.8:," "))', ibset(i, 0) ! 00000001
    print '(*(B8.8:," "))', ibset(i, 7) ! 10000000
    !
    !  ibset(i, 0)
    !
    !            ビットを1にする位置
    !            v
    !   i 00000000   ->  result 00000001
    ! pos 76543210
end program main

ibclr

整数型変数あるいは整数リテラルの,指定された位置のビットを0に置き換えた値を整数で返します.

書式

  • result = ibclr(i, pos)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • posは整数で,0以上iのビットサイズ未満の値.
      • posは配列でもよい.
      • iposの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • posが配列の場合,resultposと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11111111', kind=int8)
    print '(*(B8.8:," "))', ibclr(i, 0) ! 11111110
    print '(*(B8.8:," "))', ibclr(i, 7) ! 01111111
    !
    !  ibclr(i, 7)
    !
    !     ビットを0にする位置
    !     v
    !   i 11111111   ->  result 01111111
    ! pos 76543210
end program main

ibits

整数型変数あるいは整数リテラルの,指定された範囲のビットを取り出して右詰し,残りのビットに0を設定した値を整数で返します.取り出す範囲は,ビットの位置と,その位置から上位桁方向の長さで指定します.

書式

  • result = ibits(i, pos, len)
    • iは整数(1, 2, 4, 8バイト).
    • posは整数で,0以上の値.
      • pos+leniのビットサイズ以下.
    • lenは整数で,0以上の値.
      • pos+leniのビットサイズ以下.
    • resultは整数.
      • kindはiと同じ.
      • posが配列の場合,resultも配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'11110000', kind=int8)
    print '(*(B8.8:," "))', ibits(i, 2, 4) ! 00001100
    !
    ! ibits(i, 2, 4)
    !
    !   抜き出すビット
    !       <--> len               抜き出されたビット
    !          v pos               v--v
    !   i 11110000  ->  result 00001100
    ! pos 76543210
    !                          ^--^
    !                          0詰め
end program main

merge_bits

二つの整数変数,整数リテラルあるいはBOZリテラルを一つに併合し,結果を整数として返します.併合のする際にどちらのビットを採用するかは,追加の整数型引数に基づいて決定されます.
簡単に,第3引数のビットが1の位置は第1引数のビットが選ばれ,0の位置は第2引数のビットが選ばれると理解して問題ありません.

書式

  • result = merge_bits(i, j, mask)
    • i, jは整数(1, 2, 4, 8バイト)もしくはBOZリテラル.
      • i, jのどちらもBOZリテラルであってはならない.
      • i, jの整数kindは同じでなければならない.
    • maskは整数(1, 2, 4, 8バイト).
      • maskの整数kindは,i, jと同じでなければならない.
    • resultは整数.
      • kindはiと同じ.
      • maskのビットが1の桁ではiのビット,0の桁ではjのビットと同じ値.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j, mask

    i = int(B'01001101', kind=int8)
    j = int(B'10110010', kind=int8)
    mask = int(B'11111111', kind=int8)
    print '(*(B8.8:," "))', merge_bits(i, j, mask) ! 01001101
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j, mask

    i = int(B'01001101', kind=int8)
    j = int(B'10110010', kind=int8)
    mask = int(B'00000000', kind=int8)
    print '(*(B8.8:," "))', merge_bits(i, j, mask) ! 10110010
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i, j, mask

    i = int(B'01001101', kind=int8)
    j = int(B'10110010', kind=int8)
    mask = int(B'11110000', kind=int8)
    print '(*(B8.8:," "))', merge_bits(i, j, mask) ! 01000010
end program main

mvbits

整数型変数あるいは整数リテラル内の,指定した範囲のビットを他の整数型変数にコピーします.

書式

  • call mvbits(from, frompos, len, to, topos)
    • fromは整数(1, 2, 4, 8バイト).
    • fromposは整数で,0以上の値.
      • frompos+lenfromのビットサイズ以下.
    • lenは整数で,0以上の値
      • frompos+lenfromのビットサイズ以下.
    • toは整数型変数.
      • kindはfromと同じ.
      • toの値は,元々保持していたビット列に,fromfrompos桁から上位ビットの方向に長さlenのビット列を,toposの位置に上書きした値となる.
    • toposは整数で,0以上の値.
      • topos+lentoのビットサイズ以下.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: from, to

    from = int(B'00001111', kind=int8)
    to = int(B'11100001', kind=int8)

    call mvbits(from, 2, 4, to, 3)
    print '(*(B8.8:," "))', to ! 10011001
    !
    ! call mvbits(from, frompos, len, to, topos)
    !
    !                                抜き出されたビットが設定される
    !          <--> len              0011
    !             v frompos             v topos
    ! from   00001111          to   11100001    -> 10011001
    !  pos   76543210               76543210
    !
end program main

transfar

ビット列を他の表現として解釈します.

書式

  • result = transfer(source, mold[, size])
    • sourceは任意の型の変数あるいはリテラル.
      • sourceはスカラでも配列でもよい.
    • moldは任意の型の変数あるいはリテラル.
      • moldsourceを解釈するための手本として用いられる.
      • moldはスカラでも配列でもよい.
    • sizeは整数型.
      • sizeが省略され,moldがスカラの場合,resultはスカラ.
      • sizeが省略され,moldが配列の場合,resultは1次元配列.
      • sizeが指定されると,resultは大きさがsizeの1次元配列.
    • resultmoldと同じ型で,sourceと同じビット列を持つ.
      • スカラか配列かは,moldおよびsizeの指定で決まる.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: i
    real(real32) :: r

    r = 1.0
    i = transfer(r, mold=i) ! 単精度浮動小数点の1.0を表現するビット列を整数に変換する.
    print '(B32.32," ",B32.32)', i, r ! 00111111100000000000000000000000 00111111100000000000000000000000 ! NAG Fortranでは,実数に対してB型編集記述子が適用できないため,エラーが出る
    print *, i, r                     ! 1065353216   1.00000000

    ! 1.0の一つ隣の単精度浮動小数点の値を計算する
    r = transfer(i + 1, mold=r)
    print *, r, spacing(1.0)  ! 1.00000012       1.19209290E-07
end program main

特性値のしゅとく

ビット表現に関係する値を取得する手続を紹介します.

storage_size

引数の変数が占有するメモリサイズをビット単位で返します,

書式

  • result = storage_size(a[, kind])
    • aは任意の型の実体.
    • kindは整数kindを表す整数.
    • resultは整数で,単位は[bit].
      • kindが省略された場合,resultのkindはinteger型のkindと同じ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none

    print *, storage_size(0_int8) ! 8
    print *, storage_size(0_int16) ! 16
    print *, storage_size(0_int32) ! 32
    print *, storage_size(0_int64) ! 64
end program main

bit_size

整数型変数あるいは整数リテラルのビット数を返します.

書式

  • result = bit_size(i)
    • iは整数(1, 2, 4, 8バイト).
    • resultiのビット数.
      • resultのkindはiのkindと同じ.

    use, intrinsic :: iso_fortran_env
    implicit none

    print *, bit_size(0_int8) ! 8
    print *, bit_size(0_int16) ! 16
    print *, bit_size(0_int32) ! 32
    print *, bit_size(0_int64) ! 64
end program main

btest

整数型変数,整数リテラルにおいて,指定した桁のビットが1か否かを検査し,結果を論理型で返します.

書式

  • result = btest(i, pos)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • posは整数で,0以上iのビット数以下の値.
      • posは配列でもよい.
      • iposの両方を配列とする場合,配列の形状は同じでなければならない.
    • resultは論理型.
      • ipos桁目のビットが1の場合は真,0の場合は偽.
      • iが配列の場合,resultiと同じ次元,要素数の配列.
      • posが配列の場合,resultposと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'01010101', kind=int8)
    print *, btest(i, 0) ! T
    print *, btest(i, 1) ! F
end program main

leadz

整数型変数,整数リテラルの中で,1になっている最も上位のピットよりも上位にある0の数を返します.

書式

  • result = leadz(i)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • resultは整数
      • iのビットがすべて0の場合,0の個数が得られる(=ビットサイズと等しい).
      • kindはinteger型のkindと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'00010100', kind=int8)
    print *, leadz(i) ! 3
end program main

trailz

整数型変数あるいは整数リテラル内の,1になっている最も下位のビットよりも下位にある0の数を返します.

書式

  • result = trailz(i)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • resultは整数
      • iのビットがすべて0の場合,0の個数が得られる(=ビットサイズと等しい).
      • kindはinteger型のkindと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'00010100', kind=int8)
    print *, trailz(i) ! 2
end program main

popcnt

整数型変数,整数リテラル内の1となっているビットの数を返します.

書式

  • result = popcnt(i)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • resultは整数
      • kindはinteger型のkindと同じ.
      • iが配列の場合,resultiと同じ次元,要素数の配列.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'0101010', kind=int8)
    print *, popcnt(i) ! 3
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'0111010', kind=int8)
    print *, popcnt(i) ! 4
end program main

poppar

整数型変数,整数リテラル内の1となっているビットの数が奇数の場合に1,偶数の場合に0を返します.

書式

  • result = poppar(i)
    • iは整数(1, 2, 4, 8バイト).
      • iは配列でもよい.
    • resultは整数で,0または1.
      • kindはinteger型のkindと同じ.

program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'0101010', kind=int8)
    print *, poppar(i) ! 1
end program main
program main
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int8) :: i

    i = int(B'0111010', kind=int8)
    print *, poppar(i) ! 0
end program main
6
2
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
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?