【问题标题】:Bit twiddling for checking whether a number is in particular range用于检查数字是否在特定范围内的位旋转
【发布时间】:2011-06-02 04:55:38
【问题描述】:

我在 ICU 库(Unicode 的国际组件)的 "source\common\unicode\utf.h" 文件中发现了一些有趣的问题。位旋转用于检查数字是否在特定范围内。

// Is a code point in a range of U+d800..U+dbff?
#define U_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)

我已经弄清楚神奇数字(0xfffffc00)来自:

MagicNumber = 0xffffffff - (HighBound - LowBound)

但是,我还发现该公式并不适用于每个任意范围。有人知道这个公式在什么情况下有效吗?

检查一个数字是否在特定范围内还有其他一些小技巧吗?

【问题讨论】:

标签: c++ c algorithm bit-manipulation


【解决方案1】:

要应用这些技巧,数字必须在其二进制表示中具有一些共同特征。

0xD800 == 0b1101_1000_0000_0000
0xDBFF == 0b1101_1011_1111_1111

这个测试真正做的是屏蔽低十位。这通常写成

onlyHighBits = x & ~0x03FF

在此操作(“而不是”)之后,onlyHighBits 的低十位保证为零。这意味着如果这个数字现在等于区间的下限,那么它之前已经在区间的某个位置。

这个技巧适用于区间的下限和上限以二进制相同数字开头的所有情况,并且在某些时候下限只有零,而上限只有一。在您的示例中,它位于右侧的第十个位置。

【讨论】:

  • 你能提供任何关于“通常写成”的参考吗?我个人觉得a &~ b而不是a & ~b不太直观,a & b == ca & ~d == e更直观,因为即使这只是我个人的喜好,操作也更少。
  • 请注意,a & b == c 并不意味着您可能认为的意思(它的意思是 a & (b == c))。 a &~ b 在词汇上与 a & ~b 相同,我同意后者是对它的更好的转录,只是因为它通常是这样做的。
【解决方案2】:

如果您没有 2^x 边界类型,可以使用以下技巧:

如果 x >= 0x < N 您可以通过以下方式检查两者:

  if Longword( x ) < Longword( N ) then ...

这是因为有符号数中的负数对应于无符号数据类型中的最大数。

您可以将此(禁用范围检查时)扩展为:

  if Longword( x - A ) < Longword ( ( B - A ) ) then ...

现在您在 SUB 和 CMP 中都有两个测试(范围 [ A, B &gt;)和一个 Jcc,假设 (B - A ) 是预先计算的。

我只在真正需要时使用这些优化;例如,它们往往会降低您的代码的可读性,并且每次测试只会减少几个时钟周期。

喜欢 C 语言的读者注意:Longword 是 Delphi 的无符号 32 位数据类型。

【讨论】:

  • 感谢@Ritsaert,来自我的 +1。
【解决方案3】:

只要您要查找的范围以 2 的幂的倍数开始(即数字的二进制形式的低端的 1 位或更多位以 0 结尾)并且范围是 2^n-1(即 low&high == low 和 low|high == high)。

【讨论】:

  • 你测试了吗?假设数字为9,范围为8..8+(2^14-1),则公式不适用于这种情况。
  • 嗯... N 需要不大于基数末尾的 0 的数量(因此对于 8,N 可以在 1-3 的范围内)。我认为这太明显了,无法提及。
猜你喜欢
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 2014-12-05
  • 1970-01-01
  • 2017-05-16
  • 2014-05-05
  • 2021-03-15
相关资源
最近更新 更多