在JavaScript中有效地计算整数中的位数
假设我有一个整数,我想得到二进制形式的1的计数 我目前正在使用以下代码在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
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));