位运算博大精深,本文总结下基本的位运算的概念。

1、整数的二进制码


位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值。ECMAScript中的所有数值都以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换成32位的整数,然后执行操作,最后再将结果转换回64位。对于开发人员来说,由于64位存储格式是透明的,因此整个过程就像是只存在32位的整数一样。

对于有符号的整数,32位中的前31位用于表示整数的值。第32位用于表示数值的符号:0表示正数,1表示负数。这个表示符号的位叫做符号位。例如,数值18的二进制表示是00000000000000000000000000010010,或者更简洁的10010

负数同样以二进制码存储,但使用的是二进制补码(其实正数也是用补码表示)。计算一个数值的二进制补码,需要经过下列三个步骤:

  1. 求这个数值绝对值的二进制码
  2. 求二进制反码,即将0替换为1,将1替换为0
  3. 得到的二进制反码加1

比如求-18的二进制码,首先求得18的二进制码:

0000 0000 0000 0000 0000 0001 0010

然后求其二进制反码:

1111 1111 1111 1111 1111 1110 1101

最后,二进制反码+1

1111 1111 1111 1111 1111 1110 1110

这样就求得了-18的二进制表示。

在ECMAScript中,当对数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成32位数值,然后执行位操作,最后再将32位的结果转换回64位数值。这样,表面上看起来就好像是在操作32位数值。但这个转换过程也导致了一个严重的负效应,即在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。如果对非数值进行位操作,会先使用Number()函数将该数值转换成一个数值(自动完成),然后再应用位操作,得到的结果是一个数值。

2、~ & | ^


接下来介绍4个位操作符。

按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。

var num = 25;
console.log(~num); // -26

对25执行按位非操作,结果得到了-26,这也验证了之前说的结论,“一个负数的二进制码是该数绝对值的反码+1”

按位与操作符由一个和号字符(&)表示,它有两个操作符数,按位与操作只在两个数值的对应位都是1时才返回1,否则0。

按位或操作符由一个竖线符号(|)表示,同样也有两个操作符,在有一位是1的情况下返回1,否则0.

按位异或操作符由一个插入符号(^)表示,在两个数值对应位上只有一个1时返回1,否则0。

3、<< >> >>>


左移符号由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。在左移后,原数值右侧空出的位由0填补。

左移一位其实就相当于将原数值乘以2,左移不会影响操作数的符号位。

右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位。在移位过程中,空缺位出现在原数值的左侧,符号位的右侧,用符号位的值来填充空位。右移一位相当于原数除2后向下取整。

无符号右移操作符由三个大于号(>>>)表示,这个操作符会将数值的所有32位都向右移动。对正数来说,无符号右移的结果和有符号相同,但是对负数来说就不一样了,无符号右移会把负数的符号位也进行移动,左边空出位置用0填充。

var num = -64;
console.log(num >> 5); // -2
console.log(num >>> 5); // 134217726 

对-64进行无符号右移操作,将其用二进制码表示:

1111 1111 1111 1111 1111 1111 1100 0000

右移5位后:

0000 0111 1111 1111 1111 1111 1111 1110

即十进制的134217726。

notice:并没有无符号左移!

4、关于位运算的坑


了解的基本的位运算操作后,这里我要谈谈我经常碰到的一个坑。

int32的取值范围是-2^31 ~ 2^31-1,于是我经常会去求1<<31的值,但是是溢出的...

console.log(1 << 31); // -2147483648 

原因很简单,1的左边只有30位可以移动,实际上把1移到了符号位上,得到了:

1000 0000 0000 0000 0000 0000 0000 0000

所以要表示int32的区间范围,可以这样:

console.log(1 << 31); // -2147483648
console.log(1 << -1); // -2147483648
console.log(-0x80000000); // -2147483648

console.log(~(1 << 31)); // 2147483647
console.log(-(1 << -1) - 1); // 2147483647
console.log(0x7fffffff); // 2147483647
console.log(Math.pow(2, 31) - 1); // 2147483647
console.log((1 << 30) * 2 - 1); // 2147483647

javascript 位运算的更多相关文章

  1. JavaScript 位运算总结&拾遗

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

  2. javascript位运算

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

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

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

  4. 位运算总结&拾遗

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

  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. android项目中配置NDK自动编译生成so文件

    1 下载ndk开发包   2 在android 项目中配置编译器(以HelloJni项目为例)  2.1 创建builer  (a)Project->Properties->Builder ...

  2. VMWare克隆之后设置eth0

    [root@hadoop001 ~]# cd /etc/udev/rules.d/ [root@hadoop001 rules.d]# vim 70-persistent-net.rules 将eth ...

  3. 编写BinIoDemo.java的Java应用程序,程序完成的功能是:完成1.doc文件的复制,复制以后的文件的名称为自己的学号姓名.doc。

    package zuoye; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; ...

  4. spring服务定位器类

    此文章是基于 搭建SpringMVC+Spring+Hibernate平台 功能:通过持有的Spring应用场景ApplicationContext,可在任何地方获取bean. 1. 服务定位器类:S ...

  5. 列表list

    Python是一种面向对象的语言,但它不像C++一样把标准类都封装到库中,而是进行了进一步的封装,语言本身就集成一些类和函数,比如print,list,dict etc. 给编程带来很大的便捷 Pyt ...

  6. android xml 布局错误(黑掉了)Missing styles. Is the correct theme chosen for this layout?

    发现在调整页面的时候 ,老是报以下错误,导致无法静态显示ui效果. Missing styles. Is the correct theme chosen for this layout? Use t ...

  7. jmeter 性能测试 JDBC Request (查询数据库获取数据库数据) 的使用

    JDBC Request 这个Sampler可以向数据库发送一个jdbc请求(sql语句),并获取返回的数据库数据进行操作.它经常需要和JDBC Connection Configuration配置原 ...

  8. [译] 企业级 OpenStack 的六大需求(第 3 部分):弹性架构、全球交付

    全文包括三部分: 第一部分:API 高可用和管理以及安全模型 第二部分:开放架构和混合云兼容 第三部分:弹性架构和全球交付 需求 5 - 扩展.弹性和性能 企业级的内容很丰富.过去,企业级往往和高可靠 ...

  9. 基本开题的感觉是了-MySQL继续继续(自定义函数&存储过程)

    hi 感觉论文开题基本确定了,凯森 1.MySQL -----自定义函数----- ----基本 两个必要条件:参数和返回值(两者没有必然联系,参数不一定有,返回一定有) 函数体:合法的SQL语句:以 ...

  10. MMORPG大型游戏设计与开发(客户端架构 part5 of vegine)

    客户端异常捕获,是一件必然的事情,特别是在开发的时候就更需要这些有利于找出问题原因的捷径.区别于服务器的是,客户端基本上是以界面为主,你很难在正常运行程序的情况下进行一些输出的监视,如一些日志的记录. ...