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

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. OSGI入门笔记

    OSGI框架为Java定义了一个动态模块化系统,它使你可以更好地控制代码结构,动态管理代码的生命周期,并且提供了代码写作的松耦合方式:更值得称道的是,它的规范文档描述详尽.--<OSGI实战&g ...

  2. android ProGuard 代码混淆实现

    1 修改project.properties,添加ProGuard配置项 proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt: ...

  3. 5个示例带你学习AngularJS

    直到现在,你或许已经听说过AngularJS了,一个改变你对web应用思考方式,由谷歌开发的令人兴奋的开源框架.关于它的文章已经写得非常之多,但我发现还是要写些给那些更喜欢快速且实际例子的开发者.当今 ...

  4. webconfig 文件加密处理

    前几日正好遇到配置文件加密解密的问题,简单记录下流程. 1.首先运行cmd然后打开Framework.cd C:\Windows\Microsoft.NET\Framework\v4.0.303192 ...

  5. Nginx状态码499

    1.问题描述 140.207.202.187 - - [18/May/2016:10:30:58 +0800] "POST/v3/violations HTTP/1.1" 499 ...

  6. iOS实现自定义进度条、拖动条效果,可多个

    项目用到的一个场景,需要设置一个周期内不同时间时的数值 比如要设置10秒内,每一秒的大小,通过10个拖动条来设置实现,只需拖动到想要的数值即可, 这里周期10秒和每个拖动条的最大值都是可以自己定义的. ...

  7. C# ADO.NET编写简单的图书馆管理软件

    使用软件: Microsoft SQL Server 2012 Microsoft Visual Studio 2012 本文地址: http://www.cnblogs.com/go2bed/ 参考 ...

  8. 构建 ARM Linux 4.7.3 嵌入式开发环境 —— BusyBox 构建 RootFS

    上一篇我们已经成功将 ARM Linux 4.7.3 的内核利用 U-BOOT 引导了起来.但是细心的你会发现,引导到后面,系统无法启动,出现内核恐慌 (Kernel Panic). 原因是找不到文件 ...

  9. Vim命令大全

    1.进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文件,并将光标置于 ...

  10. 老话题:自己编写只截窗口客户区的截屏软件(VB2010)

    现在能实现截屏的软件很多,就不一一列举了,连WIN7都自带截屏软件,甚至OFFICE2010开始都有截屏的功能. 截屏软件虽多,无外乎三种截屏方式:全屏截图.窗口截图.自定义矩形截图. 其中,窗口截图 ...