javascript 二进制运算技巧解析


Posted in Javascript onNovember 27, 2012

1、原码、反码、补码,正数减法转补码加法
js 在进行二进制运算时,使用 32 位二进制整数,由于 js 的整数都是有符号数,最高位0表示正数,1表示负数,因此,js 二进制运算中使用的整数表达范围是

-Math.pow(2,31) ~ Math.pow(2,31)-1 // -2147483648 ~ 2147483647

原码:最高位 0 表示正,1表示负,其余 31 位是该数的绝对值(真值的绝对值)的二进制形式
反码:正数反码与原码相同,负数反码是原码符号位不变,其余31位取反(0变1,1变0)
补码:正数补码与原码相同,负数补码为反码加 1 (符号位参与运算,其实只有求 -0 的补码才涉及最高位进位,因此不用担心在反码加1时由于符号位参与运算进位而使 - 变 +)。
+0 的反码:32个0 ,按正数处理,原码、反码、补码都是0。
-0 的反码:最高位1,其余位由 +0 原码取反,得到 32 个 1
-0 的补码:其反码是 32 个 1 加 1,最高位溢出被舍弃,得到 32 个0
因此,正负 0 的补码都是 0.
由负数的补码求他的绝对值补码:负二进制数的绝对值,只要各位(包括符号位)取反,再加1,就得到其绝对值。
计算机在处理加减运算时,使用补码进行运算,减法被视为加上一个负数,在处理负数时,用负数的补码进行加法可以即可得到正确运算结果,补码是为了统一加减运算而生的。
正数减法转补码加法的原理是 32 位数溢出:
对于32 位二进制正整数来说,其模为
Math.pow(2,32) = 4294967296

32 位正整数最大表达范围是 4294967296 - 1 ,达到 4294967296 这个值就要进位到33位,33 位是溢出位被丢弃,只得到32 个0(这个道理跟表盘上 0 点 和12 点的时针指在同一个位置是一样的,表盘以 12 为模),因此,一个数逐渐增大,一旦超出 4294967296-1 的数 M 就可以表示为 M%4294967296
而负数 -M (M为绝对值)可以表示为一个正数: 4294967296 - M(这个正数就是负数的补码对应的二进制正整数,负数的补码按32位二进制数,与他的原码相加刚好等于模 ),道理跟表盘一样,11点和负1点指在同一个位置。
以 -3 为例:
(Array(32).join("0")+(3).toString(2)).slice(-32); // |-3| 的二进制数,即原码 
原码 = 00000000000000000000000000000011; 
反码 = 11111111111111111111111111111100; //原码符号位为1,其余位取反 
补码 = 11111111111111111111111111111101; //反码加1因为反码由正数形式的原码低31位取反得到,因此这两个数的低31位全都是1,加上反码符号位1,得到32 个1 
那么,有 
补码+原码 = (反码+1)+原码 
= (反码+原码)+1 
= 1+(32位全是 1 的二进制数) //因为反码由正数形式的原码的低31位取反加上符号位1得到,因此这两个数的和的低31位全都是1,加上反码符号位1,得到32 个1 
= Math.pow(2,32) 
= 4294967296 //这正是32位二进制数的模, 跟 |-1|+11 = 12 原理一样

这就是: 正数减法 -> 负数加法 -> 补码加法 的过程。
2、位运算
因为 js 的整数默认是带符号正数,所以在为运算中,只能使用 31 位,开发者是不能访问最高位的。
位运算只发生在整数上,因此一个非浮点数参与位运算之前会被向下取整。
为了避免访问符号位, javascript 在现实 负数的 二进制时,转换为 符号及 其绝对值的二进制,如:
(-123).toString(2) ;// "-1111011"

按位取反(~): 一元运算, 1 变0,0变1 ,如
~123 ; //-124
可以验证一下这个过程:正数取反,符号位为负,所以结果是一个负数,根据 Math.pow(2,32) - M 可以表示成 -M,可以按下面方法计算
parseInt((Array(32).join(0)+ (123).toString(2)).slice(-32).replace(/\d/g,function(v) { 
return (v*1+1)%2; 
}),2)-Math.pow(2,32) // -124 ,如果是负数减 Math.pow(2,32)

需要注意的是, javascript 位运算都是有符号的,因此达到 32 位,其最高位将作为 符号位,取反时应得到正数(取模 Math.pow(2,32) 的补数--两个数相加得到模,称这两个数互为补数)。
对整数 M 按位取反可以这样算:
((-1*M-1)+Math.pow(2,32))%Math.pow(2,32)

按位与(&):两个数的相同位,都是 1 返回1 ,否则返回0
&234 = 106 
"00000000000000000000000001111011" 
"00000000000000000000000011101010" 
--------------------------------------------- 
"00000000000000000000000001101010"

|234 = 251 
"00000000000000000000000001111011" 
"00000000000000000000000011101010" 
--------------------------------------------- 
"00000000000000000000000011111011"

按位异或(^):两个数的相同位,一个是 1 另一个是 0 则返回 1,否则返回0
^234 = 145 
"00000000000000000000000001111011" 
"00000000000000000000000011101010" 
--------------------------------------------- 
"00000000000000000000000010010001"

异或运算的一些特性:
a ^ a = 0 
a ^ b = b ^ a
 
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c 
a ^ b ^ a = b 
d = a ^ b ^ c 可以推出 a = d ^ b ^ c //这个特性被用在一些加密算法中 
//如果运算数在适当范围内(不溢出), 如 a=1,b=2,交换两个变量的值 
a = [b,b=a][0] 
//或者 
a = a^b 
b = a^b 
a= a^b

利用位的异或运算使用一个数字记录多个信息:
有几个状态值分别是 1、2、8、16 .....
这些值的规律是,他们的二进制只有一位是 1 ,其余都是 0, 因此, 他们中的任意几个的按位异或运算的结果都不会出现 两个数的某一位都是 1 的情况,并且运算的值都是唯一确定的,也就是,知道运算的结果,就知道是哪几个数的组合,这样可以用一个数字记录多个信息。
00000001 
00000010 
00000100 
00001000 
00010000

1^2^4 = 7 // "00000111"
因此,如果我们知道结果是 7 ,就知道他们是由 1 、2、4 组合而成。
如果我们要设置一个参数,使其包含几个状态值,就可以用 按位或运算,
这样的例子可以参考 PHP 中关于图片类型的几个常量,和 PHP 错误等级定义的几个常量。
这样的例子,也许有用十进制数来描述的,比如: 个位数的数字表示某个属性的状态,十位数的数字表示另一个属性的状态,这样的话,每个状态可以有 10 个值,只用一个数字就可以描述的组合非常多。
左移位(<<) : 一个数的二进制所有位向左移动,符号位不动,高位溢出丢弃,低位补 0
如果不溢出, 左移位的效果是乘以 2。
右移位(>>): 一个数的二进制所有位向右移动,符号位不动,高位补0,低位丢弃
右移位操作的效果是除以 2 并向下取整。
带符号右移(>>>):移位时符号位跟随移动,符号位也作为数值看待,所以,该操作的结果是 32 位无符号整数,因此负数的带符号右移将产生正整数,正数的带符号右移与 无符号右移相同,这是唯一可以操作符号位的运算。
-123>>>1 ;//2147483586
一些要注意的地方
位运算必须是整数,如果运算元不是可用的整数,将取 0 作为运算元
~NaN; // 将执行 ~0 ,结果为 -1 
~'x'; // -1 
'hello'|0; // 0 
({})|0 ; //0

位移运算不能移动超过31位,如果试图移动超过31位,将位数 对32取模后再移位
123>>32 //实际是 123>>0 (32%32 = 0)
123>>33 //实际是 123>>1
32位带符号整数表达范围是 -Math.pow(2,31) ~ Math.pow(2,31)-1 即 -2147483648~2147483647,而 js 数字的精度是双精度,64位,如果一个超过 2147483647 的整数参与位运算的时候就需要注意,其二进制溢出了,截取32位后,如果第32位是1将被解读为负数(补码)。
>>0; //-2147483648 
>>0; //0 
>>0; //-1 
>>0; //1
Javascript 相关文章推荐
由prototype_1.3.1进入javascript殿堂-类的初探
Nov 06 Javascript
Javascript 读书笔记索引贴
Jan 11 Javascript
jQuery实现在最后一个元素之前插入新元素的方法
Jul 18 Javascript
ExtJs异步无法向外传值和赋值的完美解决办法
Jun 14 Javascript
浅谈原型对象的常用开发模式
Jul 22 Javascript
jQuery中图片展示插件highslide.js的简单dom
Apr 22 jQuery
vue中的provide/inject的学习使用
May 09 Javascript
解决vue接口数据赋值给data没有反应的问题
Aug 27 Javascript
vue中利用Promise封装jsonp并调取数据
Jun 18 Javascript
原生js实现针对Dom节点的CRUD操作示例
Aug 26 Javascript
浅谈如何优雅处理JavaScript异步错误
Nov 12 Javascript
微信小程序视频弹幕发送功能的实现
Dec 28 Javascript
JavaScript prototype属性深入介绍
Nov 27 #Javascript
Knockoutjs的环境搭建教程
Nov 26 #Javascript
jquery ajax请求实例深入解析
Nov 26 #Javascript
jquery validate poshytip 自定义样式
Nov 26 #Javascript
一个可拖拽列宽表格实例演示
Nov 26 #Javascript
JS编程小常识很有用
Nov 26 #Javascript
javascript:history.go()和History.back()的区别及应用
Nov 25 #Javascript
You might like
攻克CakePHP系列三 表单数据增删改
2008/10/22 PHP
PHP容易被忽略而出错陷阱 数字与字符串比较
2011/11/10 PHP
Uncaught exception com_exception with message Failed to create COM object
2012/01/11 PHP
PHP采集类Snoopy抓取图片实例
2014/06/19 PHP
WordPress中对访客评论功能的一些优化方法
2015/11/24 PHP
PHP创建自己的Composer包方法
2018/04/09 PHP
PHP工厂模式的日常使用
2019/03/20 PHP
JS操作XML中DTD介绍及使用方法分析
2019/07/04 PHP
javascript 处理null及null值示例
2014/06/09 Javascript
javascript中attachEvent用法实例分析
2015/05/14 Javascript
javascript巧用eval函数组装表单输入项为json对象的方法
2015/11/25 Javascript
java必学必会之static关键字
2015/12/03 Javascript
微信小程序 Canvas增强组件实例详解及源码分享
2017/01/04 Javascript
JQuery实现定时刷新功能代码
2017/05/09 jQuery
jQuery图片缩放插件smartZoom使用实例详解
2017/08/25 jQuery
Vue中render函数的使用方法
2018/01/31 Javascript
详解vue移动端日期选择组件
2018/02/22 Javascript
5分钟学会Vue动画效果(小结)
2018/07/21 Javascript
vue组件从开发到发布的实现步骤
2018/11/11 Javascript
基于vue实现滚动条滚动到指定位置对应位置数字进行tween特效
2019/04/18 Javascript
jQuery控制input只能输入数字和两位小数的方法
2019/05/16 jQuery
开源一个微信小程序仪表盘组件过程解析
2019/07/30 Javascript
el-table树形表格表单验证(列表生成序号)
2020/05/31 Javascript
[07:08]2014DOTA2西雅图国际邀请赛 小组赛7月11日TOPPLAY
2014/07/11 DOTA
[38:23]完美世界DOTA2联赛循环赛 FTD vs PXG BO2第二场 11.01
2020/11/02 DOTA
django 实现电子支付功能的示例代码
2018/07/25 Python
python多线程抽象编程模型详解
2019/03/20 Python
小学美术教学反思
2014/02/01 职场文书
八一建军节部队活动方案
2014/02/04 职场文书
知识改变命运演讲稿
2014/05/21 职场文书
水利水电建筑施工应届生求职信
2014/07/04 职场文书
教师个人查摆剖析材料
2014/10/14 职场文书
2014年社区卫生工作总结
2014/12/18 职场文书
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
2021/05/25 Vue.js
SQL解决未能删除约束问题drop constraint
2022/05/30 SQL Server
PostgreSQL之连接失败的问题及解决
2023/05/08 PostgreSQL