如何仅使用数学从 16 位寄存器中提取特定位?

How can I extract a specific bit from a 16-bit register using math ONLY?

我有一个 16 位的 WORD,我想读取特定位或几个位的状态。

我尝试了一种方法,将单词除以我想要的位,将结果转换为两个值——一个整数和一个实数,然后比较两者。如果它们不相等,则等于 false。这似乎只有在我寻找单词中最后 'TRUE' 位的位时才有效。如果有任何连续的 TRUE 位,则失败。也许我只是没有做对。我没有使用代码的能力,只有基本的数学、布尔运算和类型转换。有任何想法吗?我希望这不是一个愚蠢的问题,但我有一种感觉。

例如:

字 0010000100100100 = 9348

我想知道第 2 位的值,如何从 9348 确定它?

第n位等于字除以2^nmod2

我想你必须测试每一位,从 0 到 15(含)。

有很多种方法,取决于您可以使用的操作。看来你没有太多选择。但这应该可行,仅使用整数除法和乘法,以及相等性测试。 (伪代码):

x = 9348 (binary 0010000100100100, bit 0 = 0, bit 1 = 0, bit 2 = 1, ...)
x = x / 4 (now x is 1000010010010000
y = (x / 2) * 2 (y is 0000010010010000)
if (x == y) {
    (bit 2 must have been 0)
} else {
    (bit 2 must have been 1)
}

每次除以 2 时,都会将位向左移动一个位置(在大端表示法中)。每次乘以 2 时,都会将位移动到正确的位置。奇数将在最不重要的位置有 1。偶数的最低位为 0。如果您在整数数学中将一个奇数除以 2,然后乘以 2,如果有一个奇数位,您将丢失奇数位。所以上面的想法是先把你想知道的位移到最不重要的位置。然后,除以 2 再乘以 2。如果结果和你之前的一样,那么你关心的位肯定是0。如果结果和你之前的结果不一样,那么你关心的位肯定是1。

解释完思路后,我们可以简化为

((x / 8) * 2) <> (x / 4)

如果设置了该位,它将解析为真,如果未设置该位,则解析为假。

AND 带有掩码的单词 [1]。

在你的例子中,你对第二位感兴趣,所以掩码(二进制)是 00000010。(十进制为 2。)

在二进制中,你的字9348是0010010010000100[2]

    0010010010000100 (your word)
AND 0000000000000010 (mask)
    ----------------
    0000000000000000 (result of ANDing your word and the mask)

因为值为零,所以该位未设置。如果它不为零,则该位已设置。

此技术适用于一次提取一位。但是,如果您对提取多个位感兴趣,则可以使用不同的掩码重复使用它。

[1] 有关屏蔽技术的更多信息,请参阅 http://en.wikipedia.org/wiki/Mask_(computing)

[2] 参见 http://www.binaryhexconverter.com/decimal-to-binary-converter

您可以尝试 9348 AND 4(相当于 1<<2 - 您想要的位的索引)

9348 AND 4 

如果位已设置,应给出 4,否则应给出 0。

所以这是我想出的:3 个解决方案。一个是上面提到的 Hatchet,他的回答极大地帮助我真正理解了它是如何工作的,这对我来说是最重要的!如果我的系统支持按位运算符,那么提议的 AND 屏蔽解决方案可能会起作用,但它显然不支持。

原创技术:

( ( ( INT ( TAG / BIT ) ) / 2 ) - ( INT ( ( INT ( TAG / BIT ) ) / 2 ) ) <> 0 )

说明: 在等式的第一部分,对 TAG/BIT 进行整数除法,然后对 REAL 除以 2。在第二部分,对 TAG/BIT 执行整数除法,然后再次对 2 进行整数除法。将这两个结果与 0 进行比较。如果差值不为 0,则公式解析为 TRUE,这意味着指定位也为 TRUE。

例如:9348/4 = 2337 w/整数除法。然后 2337/2 = 1168.5 w/ REAL 除法但 1168 w/ 整数除法。 1168.5-1168 <> 0,所以结果为真。

我修改的技术:

( INT ( TAG / BIT ) / 2 ) <> ( INT ( INT ( TAG / BIT ) / 2 ) ) 

说明: 实际上与上面相同,但不是将两个结果相减并将它们与 0 进行比较,我只是比较两个结果本身。如果它们不相等,则公式解析为 TRUE,这意味着指定的位也为 TRUE。

例如:9348/4 = 2337 w/整数除法。然后 2337/2 = 1168.5 w/ REAL 除法但 1168 w/ 整数除法。 1168.5 <> 1168,所以结果为真。

Hatchet 的技术适用于我的系统:

( INT ( TAG / BIT )) <> ( INT ( INT ( TAG / BIT ) / 2 ) * 2 )

说明: 在等式的第一部分,对 TAG/BIT 进行整数除法。在第二部分中,执行整数除法 TAG/BIT,然后再次整数除以 2,然后乘以 2。比较两个结果。如果它们不相等,则公式解析为 TRUE,这意味着指定的位也为 TRUE。

例如:9348/4 = 2337。然后 2337/2 = 1168 w/整数除法。那么1168x2=2336。 2337 <> 2336 所以结果为真。正如 Hatchet 所说,此方法 'drops the odd bit'。


注意 - 9348/4 = 2337 w/ 实数除法和整数除法,但重要的是公式的这些部分使用整数除法而不是实数除法(12164/32 = 380 w/ 整数除法和 380.125 w / 实数师)

我觉得对于任何未来的读者来说,重要的是要注意上面等式中的 BIT 值不是位数,而是如果所需位置的位是二进制字符串(位 2 = 4 (2^2),位 6 = 64 (2^6))

这个解释对某些人来说可能有点过于逐字逐句,但对其他人来说可能是完美的:)

如有需要请随时comment/critique/correct我!

我只需要将整数状态代码解析为位状态,以便与某些硬件接口。这是一种对我有用的方法:

private bool resolveBitState(int value, int bitNumber)
{
    return (value & (1 << (bitNumber - 1))) != 0;
}

我喜欢它,因为它是非迭代的,不需要转换操作,并且基本上直接转换为机器代码操作,如 Shift、And 和比较,这可能意味着它确实是最优的。

为了更详细地解释,我使用 AND 运算将按位值与我感兴趣的位(值和掩码)的掩码进行比较。如果按位与运算结果为零,则该位未设置 (return false)。如果 AND 运算结果不为零,则设置该位 (return true)。 AND 运算的结果为零或位的值(1、2、4、8、16、32 ...)。因此,布尔评估比较 AND 运算结果和 0。掩码是通过取数字 1 并将其左移(按位)适当的二进制位置数 (1 << n) 创建的。位数是目标位数减1。如果是#1,我想将1左移0,如果是#2,我想将它左移1位,依此类推

我很惊讶没有人评价我的解决方案。它认为这是最合乎逻辑和最简洁的......并且有效。