fortran fortran中文资料网
手气不错
Article

047.bitIntrinsics_整数位操作内在函数

整数位操作内在函数把整数视为按位置编号的二进制位序列,可以组合、测试或修改其中的位。它们常用于用一个整数保存多个开关状态,适合在权限掩码、设备状态字、通信协议字段等需要紧凑编码布尔状态的情况中使用,并可与逻辑判断结合处理某一状态位。

位位置与运算

Fortran从0开始对位编号,位置0是最右侧的最低位,位置依次向左增加。位置参数必须满足0pos<bit_size(i)0\le pos<\operatorname{bit\_size}(i)

combined = iand(i, j)
combined = ior(i, j)
combined = ieor(i, j)
isSet = btest(i, pos)
newValue = ibset(i, pos)
newValue = ibclr(i, pos)
width = bit_size(i)
  • iand仅在两个对应位都是1时产生1;ior在至少一个对应位是1时产生1;ieor在两个对应位不同时产生1。
  • btest测试指定位并返回逻辑值;ibsetibclr返回设置或清除该位后的新整数,不会修改参数本身。
  • bit_size查询参数所属整数种类的位模型宽度,不是当前数值实际用了多少位。
  • 示例使用B4.4编辑描述符显示低四位二进制形式,便于把十进制结果与逐位运算对应起来。

本文代码

! 位操作内在函数把整数作为状态位集合处理。
program bitIntrinsicsDemo
  implicit none
  integer :: maskA, maskB

  maskA = 6
  maskB = 3

  print "(A,I2,2X,B4.4)", "maskA:", maskA, maskA
  print "(A,I2,2X,B4.4)", "maskB:", maskB, maskB
  print "(A,I2,2X,B4.4)", "IAND :", iand(maskA, maskB), iand(maskA, maskB)
  print "(A,I2,2X,B4.4)", "IOR  :", ior(maskA, maskB), ior(maskA, maskB)
  print "(A,I2,2X,B4.4)", "IEOR :", ieor(maskA, maskB), ieor(maskA, maskB)
  print "(A,L1)", "BTEST(maskA,1):", btest(maskA, 1)
  print "(A,I2,2X,B4.4)", "IBSET(maskB,2):", ibset(maskB, 2), ibset(maskB, 2)
  print "(A,I2,2X,B4.4)", "IBCLR(maskA,1):", ibclr(maskA, 1), ibclr(maskA, 1)
  print "(A,I0)", "默认整数位数:", bit_size(maskA)
end program bitIntrinsicsDemo

编译运行

(base) hong@hongdeMacBook-Pro 047.bitIntrinsics % gfortran -Wall -Wextra -std=f2018 exampleBitIntrinsics.f90
(base) hong@hongdeMacBook-Pro 047.bitIntrinsics % ./a.out
maskA: 6  0110
maskB: 3  0011
IAND : 2  0010
IOR  : 7  0111
IEOR : 5  0101
BTEST(maskA,1):T
IBSET(maskB,2): 7  0111
IBCLR(maskA,1): 4  0100
默认整数位数:32

现象分析

maskA=6的低四位是0110,maskB=3的低四位是0011。按位与、或、异或从相同位置逐列计算:

         bit3 bit2 bit1 bit0
maskA      0    1    1    0
maskB      0    0    1    1
IAND       0    0    1    0  = 2
IOR        0    1    1    1  = 7
IEOR       0    1    0    1  = 5

iand只保留两者都为1的bit 1,所以结果0010等于2;ior保留任一参数中的1,得到0111即7;ieor只保留不同的位,bit 2与bit 0不同,得到0101即5。

btest(maskA,1)检查0110从右向左编号为1的位,该位是1,因此返回.true.并显示为T。它只读取该位,不产生新的掩码。

ibset(maskB,2)把0011的bit 2设为1,得到0111,即4+2+1=7。ibclr(maskA,1)把0110的bit 1清为0,得到0100,即4。原来的maskAmaskB仍分别是6和3,因为函数返回的是新值。

本机默认整数的bit_size为32,所以有效位置是0到31。数值6只需低三位表示,但bit_size(6)查询的是默认整数种类的位宽,结果仍为32;其他编译环境或整数种类可能具有不同位宽。

核心知识点

  • Fortran位位置从0开始,位置0是最低位;位置参数必须落在整数种类的有效位范围内。
  • iandiorieor逐位产生整数结果,规则分别是“都为1”“至少一个为1”“两者不同”。
  • btest返回逻辑值;ibsetibclr返回修改后的新整数。
  • bit_size描述整数种类的位模型宽度,不描述某个正整数当前需要的最少位数。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注