在JavaScript中有效地计算整数中的位数

在JavaScript中有效地计算整数中的位数,javascript,binary,bit-manipulation,Javascript,Binary,Bit Manipulation,假设我有一个整数,我想得到二进制形式的1的计数 我目前正在使用以下代码 Number(i.toString(2).split("").sort().join("")).toString().length; 有没有更快的方法?我正在考虑使用位运算符。有什么想法吗 注意:i在32位限制内 您可以使用以下集合中的策略: 函数位计数(n){ n=n-((n>>1)和0x5555) n=(n&0x33333333)+((n>>2)和0x33333333) 返回((n+(n>>4)&0xf0f)*0x1

假设我有一个整数,我想得到二进制形式的1的计数

我目前正在使用以下代码

Number(i.toString(2).split("").sort().join("")).toString().length;
有没有更快的方法?我正在考虑使用位运算符。有什么想法吗


注意:
i
在32位限制内

您可以使用以下集合中的策略:

函数位计数(n){
n=n-((n>>1)和0x5555)
n=(n&0x33333333)+((n>>2)和0x33333333)
返回((n+(n>>4)&0xf0f)*0x1010101)>>24
}

console.log(bitCount(0xFF))/=>8
考虑到您正在创建、排序和加入一个数组,如果它确实比您想要的快,您可能最好采用令人厌烦的方式:

console.log(countone(8823475632));
函数计数(一){
var-str=i.toString(2);
var n;
var计数=0;
对于(n=0;n}
以下任何数字均可使用:

var i=8823475632,计数=0;而(i=Math.floor(i))i&1?count++:0,i/=2

控制台日志(计数)//17
您可以跳过
编号
排序
和第二个
到字符串
。使用<代码>过滤器>代码>只考虑数组中的<代码> 1 /代码> s(truthvalue),然后检索有多少代码通过<代码>长度< /> >

i.toString(2).split('').filter(v => +v).length
执行
n=n&(n-1)
将删除数字中的最后1位。 据此,您可以使用以下算法:

函数getBitCount(n){ var-tmp=n; var计数=0; 而(tmp>0){ tmp=tmp&(tmp-1); 计数++; } 返回计数; }
log(getBitCount(Math.pow(2,10)-1))一种递归的非常好但是慢的方法:
函数计数1(n,累加器=0){
如果(n==0){
回流蓄能器
}
返回计数1(n/2,累加器+(n&1))
}

log(count1(Number.MAX_SAFE_INTEGER))如果您想使用绝对的单行程序解决方案,您可以看看这个

countBits = n => n.toString(2).split('0').join('').length;
1.这里n.toString(2)将n转换为二进制字符串

2.split('0')仅在 0,因此返回一个仅为1的数组,该数组以n的二进制形式存在

3.join(“”)将所有一个连接起来,形成一个由1组成的字符串

4.length查找字符串的长度,该字符串实际计算n中1的个数。

还有几个“有趣”的单行程序:

递归:递归地计算每个位,直到没有更多的位被设置

让f=x=>!x?0:(x&1)+f(x>>=1);
功能:拆分x的基2字符串,并返回位集的累计长度

g=x=>x.toString(2).split('0').map(bits=>bits.length).reduce((a,b)=>a+b);

继续检查最后一位是否为1,然后将其删除。如果它发现最后一位为1,则将其添加到结果中

Math.popcount = function (n) {
  let result = 0;

  while (n) {
    result += n % 2;
    n = n >>> 1;
  };

  return result;
};

console.log(Math.popcount(0b1010));


对于64位,可以将数字表示为两个整数,第一个是最上面的32位,第二个是最下面的32位。要计算64位中的一个数,您可以将它们拆分为2、32位整数,然后将第一个和第二个的popcount相加。

就在我发布脚注时,您抓到了我:)我在这个按位的世界里还是个新手。什么是0x555555和0xF0F?有什么好的资源可以让我读到?谢谢。这是数字文字的十六进制表示法。
0x
只告诉您它是十六进制的;文本的其余部分是通过调用
number.toString(16)
得到的。请参阅MDN上的“使用正则表达式”-现在您有两个问题:DI只是一个正则表达式。正则表达式在这一点上非常好:D什么是I33t?所以循环实际上比创建/排序/加入更快?关于这个主题,我能读到什么资源?@MingHuang:考虑到创建、排序和加入数组都涉及到循环,是的,我打赌它会更快。我也打赌99.9999%的时间,没关系。我没有任何特定的资源给你,除了那些可以方便地进行性能比较的资源(当它出现时)。@MingHuang:是的,。我已经测试了我的答案。这比你上面给出的最快答案快了800倍@科扬:不错。有两件事:1。该测试是有缺陷的,因为您修改了
num
,它在测试之间被重用。2.您没有包含正确结果的检查,这将显示您正在将苹果与橙子进行比较。:-)如果我们将苹果与苹果进行比较,Chrome会使其速度快4倍,而Firefox则会慢三分之一。无论如何,它是聪明的;字符串
'0'
也是真实的。
reduce
在我看来,在这里更好地传达了意义(获取一系列值并返回单个值)。它还具有不必构建
'1'
s数组的优点,在这种情况下:
i.toString(2).split(“”).reduce((sum,char)=>char=='1'?+sum:sum,0)
不过要小心,对于不适合32位2的补码类型的整数,此操作将失败。必须检查规范,了解上面的
num&1
中是否正确保留低阶1。我敢肯定是的<代码>&
通过强制执行,如果我读对了,1应该是安全的。Neat.your代码不适用于i=Number.MAX_SAFE_integerware,但是,对于不适合32位2的补码类型的整数,这将失败。注意:Web程序集具有
i32.popcnt
,如果人们真的非常关心的话。我检查了。。最快的方法更简单!检查我的答案并将其标记为答案!我的代码没有32位的限制@不,最简单的是第二快的。。最快的速度是最简单的速度(count1s)的10倍。再检查一遍。投票最多的答案在3年前就已经有了。我建议你删除这个答案。
Math.popcount = function (n) {
  let result = 0;

  while (n) {
    result += n % 2;
    n = n >>> 1;
  };

  return result;
};

console.log(Math.popcount(0b1010));