最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识。

把一个数变为大于等于该数的最小的2的幂


一个数为2的幂,那么该数的二进制码只有最高位是1。

根据这个性质,我们来举个栗子,比如有数字10,转为二进制码后为:

1 0 1 0

我们只需把 0 bit的位置全部用1填充,然后再把该二进制码加1就ok了。而x | (x + 1)正好可以把最右边的0置为1,可是问题来了,当二进制码变成 1 1 1 1后,我们无法判断二进制码已经全是1了,继续操作的话会变成1 1 1 1 1,于是,该法失败...

我们可以采用类似迭代的方法,又有点分组的意思。因为最高位肯定是1,我们把init的数右移一位,和原数作与运算,这样就能把次高位也置为1,然后继续右移,这时最前面两位都是1了,右移两位后,做与运算,这时前四位都是1了:

function change2Pow(n) {
  if(!(n & (n-1)) && n > 0) return n;
  n |= n >>> 1;
  n |= n >>> 2;
  n |= n >>> 4;
  n |= n >>> 8;
  n |= n >>> 16;
  return n + 1;
}

计算二进制中1的个数


leetcode中有一道这样的题目-Number of 1 Bits,正好拿来验证程序的正确性。

常规解法不用多说,直接上代码:

var hammingWeight = function(n) {
  var ans = 0;
  while (n) {
    ans += n & 1;
    n >>>= 1;
  }
  return ans;
};

因为题目中有说是unsigned int32的整数,所以要用有符号右移>>>来操作符号位。

位运算解法和求逆序一样,也采用分组的思想。

我们以16位下的12345举例(6个1),先写出它的二进制码表示:

0011000000111001

第一步:每两个为一组,组内高低位相加

00 10 00 00 00 10 01 01

第二步:每四个为一组,组内高低位相加

0010 0000 0010 0010

第三步:每8个为一组,组内高低位相加

00000010 00000100

第四步,每16个为1组,组内高低位相加

0000000000000110

最后得到的数字6即为12345二进制码中1的个数。而实际中,因为int32是32位的,所以一共要进行5步。求解思路和求逆序类似,逆序是要交换,所以要分别左移右移,而求1的个数是相加,所以只需移动一次就够了。

完整代码:

var hammingWeight = function(n) {
  n = ((n & 0xAAAAAAAA) >>> 1) + (n & 0x55555555);
  n = ((n & 0xCCCCCCCC) >>> 2) + (n & 0x33333333);
  n = ((n & 0xF0F0F0F0) >>> 4) + (n & 0x0F0F0F0F);
  n = ((n & 0xFF00FF00) >>> 8) + (n & 0x00FF00FF);
  n = ((n & 0xFFFF0000) >>> 16) + (n & 0x0000FFFF);
  return n;
};

因为是unsigned int32,所以要用>>>如前所述。

再次击败100%的JavaScript code...

计算二进制中1的个数的奇偶性


我们可以先计算1的个数,然后再判断奇偶。当然既然作为一道独立的题目,肯定有更简便的方法。

整个过程可以用分治来解。第1步统计相邻2位的1的个数奇偶性,保存到这2位的低位中。第2步统计相邻4位的1的个数奇偶性,保存到这4位的低位中。……第5步统计相邻2位的1的个数奇偶性,保存到这32位的低位中,即x的最低位。

function bit1OddEven(x){ //奇数个为1,偶数个为0
  x ^= x >>> 1;    //相邻 2位中1的奇偶性
  x ^= x >>> 2;    //相邻 4位中1的奇偶性
  x ^= x >>> 4;    //相邻 8位中1的奇偶性
  x ^= x >>> 8;    //相邻16位中1的奇偶性
  x ^= x >>> 16;   //相邻32位中1的奇偶性
  return x & 1;
}

统计二进制前导0、末尾0的个数


先排除为0的特殊情况。然后先看前16位是否全0,如果全0,增加计数,并把这个数左移16位删除已经计数的16个0。然后看前8位是否全0。一直到只剩一位时可以直接计算。整个过程的核心是二分思想

统计末尾0的个数时思想类似,只是变成了统计后面16位、8位等是否全0。

function countLeading0(x) {
  if (!x) return 32;
  var n = 1;
  if ((x >>> 16) == 0) n += 16, x <<= 16;
  if ((x >>> 24) == 0) n += 8, x <<= 8;
  if ((x >>> 28) == 0) n += 4, x <<= 4;
  if ((x >>> 30) == 0) n += 2, x <<= 2;
  return n - (x >>> 31);
}

function countTrailing0(x) {
  if (!x) return 32;
  var n = 1;
  if ((x << 16) == 0) n += 16, x >>>= 16;
  if ((x << 24) == 0) n += 8, x >>>= 8;
  if ((x << 28) == 0) n += 4, x >>>= 4;
  if ((x << 30) == 0) n += 2, x >>>= 2;
  return n - (x & 0x01);
}

当然计算末尾0的个数,我们也可以这样:

function countTrailing0(a) {
  return Math.log(a & (-a)) / Math.LN2;
}

这个系列暂时结束了,但我知道对于位运算的学习,这只是起点。

附位运算系列目录

  1. javascript 位运算
  2. 常用位运算整理
  3. 【位运算经典应用】 标志位与掩码
  4. 【位运算经典应用】 N皇后问题
  5. 【位运算经典应用】 求二进制逆序
  6. 【位运算经典应用】 寻找那个唯一的数
  7. leetcode - 位运算题目汇总(上)
  8. leetcode - 位运算题目汇总(下)
  9. JavaScript 位运算总结&拾遗

JavaScript 位运算总结&拾遗的更多相关文章

  1. 位运算总结&拾遗

    JavaScript 位运算总结&拾遗 最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识 ...

  2. javascript位运算

    javascript作为一门高级语言,他尽量让开发人员减少思考底层的硬件工作原理,而将精力集中在逻辑开发的层面.不过,不论这门语言多么高级,我们必须知道数据依然以bits的形式存储,有时候我们会直接与 ...

  3. javascript 位运算

    位运算博大精深,本文总结下基本的位运算的概念. 1.整数的二进制码 位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值.ECMAScript中的所有数值都以IEEE-754 64位格式存储 ...

  4. leetcode - 位运算题目汇总(下)

    接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...

  5. javascript的变态位运算

    javascript的变态位运算 var a = "10" | 0; alert(a); alert (typeof a);结果为10,number. 这就是说这条语句可以将字符串 ...

  6. 【JavaScript】进制转换&位运算,了解一下?

    前言 在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它.作为一位编程人员,这些都是基础知识.如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难.本文你将会学习到: 进制转 ...

  7. javascript中的类型转换(进制转换|位运算)

    1:parseInt(string) : 这个函数的功能是从string的开头开始解析,返回一个整数 parseInt("123hua"); //输出 123 parseInt(& ...

  8. javascript中的位运算,

    罗浮宫群里又有讨论位运算符号|了,做过一段时间php,数据库保存布尔值数据经常用到,比如100110 就表明了六个属性的是与否,极大减少了数据量..] ECMAScript 中位运算跟其他语言一样的. ...

  9. js中的位运算

    按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...

随机推荐

  1. 资源list:Github上关于大数据的开源项目、论文等合集

    Awesome Big Data A curated list of awesome big data frameworks, resources and other awesomeness. Ins ...

  2. iOS 导航栏实现总结

    目标: 在UI界面中实现 整体效果的导航栏, 比如1 首页无导航条,次页有导航条, 2 导航条中不包含下方不包含黑边 3 导航条包含多个筛选项 等等 问题: 用系统带的NavigateBar 来实现时 ...

  3. W3School-CSS 文本实例

    CSS 文本实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) 实例 CSS 内边距 (paddi ...

  4. 【mysql】关于硬件方面的一些优化

    一.CPU最大性能模式 cpu利用特点 5.1 最高可用4个核 5.5 最高可用24核 5.6 最高可用64核心 一次query对应一个逻辑CPU 你仔细检查的话,有些服务器上会有的一个有趣的现象:你 ...

  5. python基础(二)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 简单的数据类型以及赋值 变量不需要声明 Python的变量不需要声明,你可以直接输 ...

  6. 优化SQL查询:如何写出高性能SQL语句

    1. 首先要搞明白什么叫执行计划? 执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的,比如一条SQL语句如果用来从一个 10万条记录的表中查1条 ...

  7. 使用Fiddler对Android或者iOS设备进行抓包

    1.PC端Fiddler配置 Tools->HTTPS->选中“Decrpt HTTPS traffic”,“Ignore server certificate errors” Tools ...

  8. <代码整洁之道>、<java与模式>、<head first设计模式>读书笔记集合

    一.前言                                                                                       几个月前的看书笔记 ...

  9. Eclipse RCP实用小技巧

    1.插件Plugin工程的build.properties中增加一行,javacDefaultEncoding.. = UTF 2.插件Plugin工程的Runtime的classpath中加入.

  10. 13款经典BI项目报表&界面风格设计方案

    说明 1.方案取自报表开发工具FineReport案例的配色方案 2.所有设计方案图中已标注了字体.颜色与间隔距离等,可直接调用. 报表&界面风格设计方案展示 灰蓝界面 绿色与金色 蓝绿清新风 ...