【问题标题】:How can I extract a specific bit from a 16-bit register using math ONLY?如何仅使用数学从 16 位寄存器中提取特定位?
【发布时间】:2015-01-13 18:27:49
【问题描述】:

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

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

例如:

字 0010000100100100 = 9348

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

【问题讨论】:

  • 您希望答案是什么样的?您希望那个孤立的位在其原始位置,还是在最不重要的位置?
  • 你可以使用按位与和移位运算符吗?
  • 我刚刚将可用的功能作为屏幕截图添加到原始问题中。我只需要能够知道一点是真还是假。该等式需要产生一个布尔值。我可以根据需要修改方程以输入我想要的位。
  • 输入 1 AND 2 会得到什么答案?另外,如果你输入 1 AND 3,你会得到什么?这将帮助我们了解您实际使用的 AND 运算符。这个问题的答案决定了下面哪些答案对你有用。
  • 按位 AND 没有骰子 :( 将是一个很棒的解决方案

标签: word bit


【解决方案1】:

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

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)

如果设置了位,则解析为 true,如果未设置,则解析为 false。

【讨论】:

  • 所以我将其简化为:((((9348/4))/2)*2) (((9348/4))/2))
  • 在本例中,最终结果应评估为位 2 的状态。 - 测试
  • 不,我认为应该是 (((9348/4)/2)*2) (9348/4),或者进一步简化为 ((9348/8)*2) (9348/4)
  • 是的,我的第一次尝试(上图)显然是错误的 :)。现在测试!
  • 我可能遗漏了一些东西.. 9348 / 8 = 1168.5, *2 = 2337 9348 / 4 = 2337 它们是相等的,所以上面的公式计算为假。但第 2 点是真的..
【解决方案2】:

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

在您的示例中,您对第二位感兴趣,因此掩码(二进制)是 00000010。(十进制为2)

在二进制中,您的单词 9348 是 0010010010000100 [2]

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

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

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

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

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

【讨论】:

  • 我不认为他可以使用按位与。
  • 图片的第四行第一列。
  • 不清楚这些是逻辑运算符还是位运算符,我无法从 OP 那里得到澄清。
  • 公平的问题。你说得对,截图不清晰。
  • 我将测试 AND 函数以获得乐趣 - 我敢打赌它只是布尔值。这是在制造过程控制系统的 HMI 上 - 我有从我们的 PLC 到我们的 SCADAS 的“WORD”标签,每个单独的设备都有很多状态位,但我只需要在屏幕上表示一个状态位。 . 其余只在PLC中使用。从历史上看,我们只会在 SCADA 中创建一个附加标签,该标签将直接从 PLC 字(寄存器:位)中引用该位
【解决方案3】:

第n位等于单词除以2^n mod 2

我认为您必须测试从 0 到 15 的每一位。

【讨论】:

  • 这似乎证明了我的原始技术,它将除法运算的两个结果(一个实数,一个整数 - 无余数)与原始 WORD 和所需位位置的十进制值进行比较:( ( ( ( ( INT ( 9348 / 4 ) ) / 2 ) - ( INT ( ( INT ( 9348 / 4 ) ) / 2 ) ) 0 ) 但如果有更重要的位,它似乎不起作用在WORD中
  • @goofology 是的,第二个模块可以忽略更重要的位。不过,看起来您不允许使用 mod。
【解决方案4】:

您可以尝试 9348 AND 4(相当于 1

9348 AND 4 

如果设置了位,则应为 4,否则为 0。

【讨论】:

  • 我的印象是他没有可用的按位和位移。
  • 我编辑了我的答案。我认为他可以按位使用,因为我在那里看到 XOR
  • 按位 AND 没有骰子 :( 将是一个很棒的解决方案
【解决方案5】:

这就是我想出的: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,所以结果为 TRUE。

我修改的技术:

( 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,所以结果为 TRUE。

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 所说,这种方法“丢弃了奇数位”。


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

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

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

如有必要,请随时评论/批评/纠正我!

【讨论】:

    【解决方案6】:

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

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

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

    为了更详细地解释一下,我使用 AND 操作将按位值与我感兴趣的位(值和掩码)的掩码进行比较。如果按位与运算结果为零,则不设置该位(返回 false)。如果 AND 运算结果不为零,则设置该位(返回真)。 AND 运算的结果是零或位的值 (1, 2, 4, 8, 16, 32...)。因此,布尔评估比较 AND 运算结果和 0。通过取数字 1 并将其向左(按位)移动适当数量的二进制位(1

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

    【讨论】:

      猜你喜欢
      • 2012-04-11
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      • 2022-10-16
      • 1970-01-01
      • 2013-05-14
      • 2012-01-11
      相关资源
      最近更新 更多