整数位操作内在函数把整数视为按位置编号的二进制位序列,可以组合、测试或修改其中的位。它们常用于用一个整数保存多个开关状态,适合在权限掩码、设备状态字、通信协议字段等需要紧凑编码布尔状态的情况中使用,并可与逻辑判断结合处理某一状态位。
位位置与运算
Fortran从0开始对位编号,位置0是最右侧的最低位,位置依次向左增加。位置参数必须满足。
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测试指定位并返回逻辑值;ibset和ibclr返回设置或清除该位后的新整数,不会修改参数本身。
- 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。原来的maskA和maskB仍分别是6和3,因为函数返回的是新值。
本机默认整数的bit_size为32,所以有效位置是0到31。数值6只需低三位表示,但bit_size(6)查询的是默认整数种类的位宽,结果仍为32;其他编译环境或整数种类可能具有不同位宽。
核心知识点
- Fortran位位置从0开始,位置0是最低位;位置参数必须落在整数种类的有效位范围内。
- iand、ior和ieor逐位产生整数结果,规则分别是“都为1”“至少一个为1”“两者不同”。
- btest返回逻辑值;ibset和ibclr返回修改后的新整数。
- bit_size描述整数种类的位模型宽度,不描述某个正整数当前需要的最少位数。