位掩码:如何确定是不是只设置了一位

Posted

技术标签:

【中文标题】位掩码:如何确定是不是只设置了一位【英文标题】:Bitmask: how to determine if only one bit is set位掩码:如何确定是否只设置了一位 【发布时间】:2013-04-11 14:44:09 【问题描述】:

如果我有一个基本的位掩码...

cat = 0x1;
dog = 0x2;
chicken = 0x4;
cow = 0x8;

// OMD has a chicken and a cow
onTheFarm = 0x12;

...如何检查是否只设置了一种动物(即一位)?

onTheFarm 的值必须是 2n,但我如何以编程方式检查(最好是 javascript)?

【问题讨论】:

查看this question。不是特定于 javascript 的,但很有趣。 谢谢 Rob,刚刚找到这个(看起来更直接)***.com/questions/1053582/… 仅供参考,OMD = Old MacDonald @rvighne: I/O, I/O, null... 【参考方案1】:

您可以使用此代码计算在非负整数值中设置的位数(从this answer 改编为 JavaScript):

function countSetBits(i)

    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;

它应该比单独检查每个位更有效。但是,如果在i中设置了符号位,则它不起作用。

编辑(全部归功于 Pointy 的评论):

function isPowerOfTwo(i) 
    return i > 0 && (i & (i-1)) === 0;

【讨论】:

哇,太好了。对此进行调查后,我发现 this reference 是针对这个特定问题的,而且看起来更好!【参考方案2】:

你必须一点一点地检查,功能或多或少是这样的:

function p2(n) 
  if (n === 0) return false;
  while (n) 
    if (n & 1 && n !== 1) return false;
    n >>= 1;
  

  return true;

一些 CPU 指令集包含“计数集位”操作(古老的 CDC Cyber​​ 系列就是其中之一)。它对于一些实现为位集合的数据结构很有用。如果你有一个集合实现为一串整数,位位置对应于集合数据类型的元素,那么获得基数涉及对位进行计数。

edit 哇,看着 Ted Hopp 的回答,我偶然发现了这个:

function p2(n) 
  return n !== 0 && (n & (n - 1)) === 0;

来自this awesome collection of "tricks"。像这样的问题是研究数论的好理由:-)

【讨论】:

【参考方案3】:

如果您想查看是否只设置了一个位,您可以利用logarithms,如下所示:

var singleAnimal = (Math.log(onTheFarm) / Math.log(2)) % 1 == 0;

Math.log(y) / Math.log(2)2^x = y 中找到xx % 1 告诉我们x 是否为整数。 x 将仅是一个整数,如果设置了一个位,因此只会选择一种动物。

【讨论】:

很高兴地忽略浮点舍入,您会得出结论, (1console.log((Math.log(1<<29) / Math.log(2)) % 1) 在我的机器上打印 3.552713678800501e-15。 有趣。我想通常使用log 的效率远低于概述为答案的其他技术。知道处理浮点舍入错误的任何方法吗? 不适用于这个问题。您可以在this article 中阅读有关问题的详细概述。它在技术上相当繁重,但如果你想深入了解浮点的底层原理,那么值得一试。 TL;DR 版本是:每个浮点运算(甚至简单地表示一个数字)都有一个错误;相应地设计您的代码。

以上是关于位掩码:如何确定是不是只设置了一位的主要内容,如果未能解决你的问题,请参考以下文章

C中的位掩码

选择位掩码中与选择器位图中的 1 位重叠的设置位范围

位掩码:通过 set 方法设置对象的不同状态

无法应用位掩码

合并两个位掩码并解决冲突,任何两个设置位之间有一些所需的距离

位掩码是不是可以与位中的“访问数组”相媲美?