一、原码、反码、补码,正数减法转补码加法
js 在进行二进制运算时,使用 32 位二进制整数,因为 js 的整数都是有符号数,最高位0表示正数,1表示负数,所以,js 二进制运算中使用的整数表达范围是 javascript
原码:最高位 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 位二进制正整数来讲,其模为 html
32 位正整数最大表达范围是 4294967296 - 1 ,达到 4294967296 这个值就要进位到33位,33 位是溢出位被丢弃,只获得32 个0(这个道理跟表盘上 0 点 和12 点的时针指在同一个位置是同样的,表盘以 12 为模),所以,一个数逐渐增大,一旦超出 4294967296-1 的数 M 就能够表示为 M%4294967296
而负数 -M (M为绝对值)能够表示为一个正数: 4294967296 - M(这个正数就是负数的补码对应的二进制正整数,负数的补码按32位二进制数,与他的原码相加恰好等于模 ),道理跟表盘同样,11点和负1点指在同一个位置。
以 -3 为例: java
这就是: 正数减法 -> 负数加法 -> 补码加法 的过程。
二、位运算
由于 js 的整数默认是带符号正数,因此在为运算中,只能使用 31 位,开发者是不能访问最高位的。
位运算只发生在整数上,所以一个非浮点数参与位运算以前会被向下取整。
为了不访问符号位, javascript 在现实 负数的 二进制时,转换为 符号及 其绝对值的二进制,如: 算法
按位取反(~): 一元运算, 1 变0,0变1 ,如
~123 ; //-124
能够验证一下这个过程:正数取反,符号位为负,因此结果是一个负数,根据 Math.pow(2,32) - M 能够表示成 -M,能够按下面方法计算 加密
须要注意的是, javascript 位运算都是有符号的,所以达到 32 位,其最高位将做为 符号位,取反时应获得正数(取模 Math.pow(2,32) 的补数--两个数相加获得模,称这两个数互为补数)。
对整数 M 按位取反能够这样算: spa
按位与(&):两个数的相同位,都是 1 返回1 ,不然返回0 .net
按位异或(^):两个数的相同位,一个是 1 另外一个是 0 则返回 1,不然返回0 :code
异或运算的一些特性: htm
利用位的异或运算使用一个数字记录多个信息:
有几个状态值分别是 一、二、八、16 .....
这些值的规律是,他们的二进制只有一位是 1 ,其他都是 0, 所以, 他们中的任意几个的按位异或运算的结果都不会出现 两个数的某一位都是 1 的状况,而且运算的值都是惟一肯定的,也就是,知道运算的结果,就知道是哪几个数的组合,这样能够用一个数字记录多个信息。 blog
1^2^4 = 7 // "00000111"
所以,若是咱们知道结果是 7 ,就知道他们是由 1 、二、4 组合而成。
若是咱们要设置一个参数,使其包含几个状态值,就能够用 按位或运算,
这样的例子能够参考 PHP 中关于图片类型的几个常量,和 PHP 错误等级定义的几个常量。
这样的例子,也许有用十进制数来描述的,好比: 个位数的数字表示某个属性的状态,十位数的数字表示另外一个属性的状态,这样的话,每一个状态能够有 10 个值,只用一个数字就能够描述的组合很是多。
左移位(<<) : 一个数的二进制全部位向左移动,符号位不动,高位溢出丢弃,低位补 0
若是不溢出, 左移位的效果是乘以 2。
右移位(>>): 一个数的二进制全部位向右移动,符号位不动,高位补0,低位丢弃
右移位操做的效果是除以 2 并向下取整。
带符号右移(>>>):移位时符号位跟随移动,符号位也做为数值看待,因此,该操做的结果是 32 位无符号整数,所以负数的带符号右移将产生正整数,正数的带符号右移与 无符号右移相同,这是惟一能够操做符号位的运算。
-123>>>1 ;//2147483586
一些要注意的地方:
位运算必须是整数,若是运算元不是可用的整数,将取 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将被解读为负数(补码)。
1.NOT
位运算符NOT由~表示.NOT运算符的实质是对数字求负,而后减1.
位运算符NOT是三步的处理过程.
a.把运算符转换成32位数字
b.把二进制形式转换成它的二进制反码
c.把二进制反码转换成浮点数
例子:
var num=10; document.write(~num);
结果:-11
2.AND
位运算符AND由&表示.直接对数字的二进制形式进行运算.运算规则以下:
第一个数字 第二个数字 结果 0 0 0 0 1 0 1 0 0 1 1 1
例子:
var num1=10;//1010 var num2=11;//1011 document.write(num1 & num2);
结果:
3.OR
位运算符OR由符号|表示.直接对二进制进行运算,规则以下:
第一个数字 第二个数字 结果 0 0 0 0 1 1 1 0 1 1 1 1
例子:
var num1=10;//1010 var num2=11;//1011 document.write(num1 | num2);
结果:
4.XOR
位运算符XOR由符号^表示.直接对二进制进行运算.规则以下:
第一个数字 第二个数字 结果 0 0 0 0 1 1 1 0 1 1 1 0
例子:
var num1=10;//1010 var num2=11;//1011 document.write(num1 ^ num2);
结果:
5.<<
左移运算符由<<表示.它把数字中全部位数向左移动指定的数量.
注意:
a.在左移数位时,数字右边的空位由0来填充,使结果是完整的32位数字
b.左移操做保留数字的符号位.
例子:
document.write(10<<2+"<br/>"); document.write(-10<<2);
效果:
6.>>
有符号右移运算由>>表示.它将32位数字中的全部数字总体右移.同时保留该数的符号.
注意:
a.符号位保持不变
b.在右移数位时,数字左边的空位由0填充
例子:
document.write(10>>1); document.write("<br/>"); document.write(-10>>1);
效果:
7.>>>
无符号右移由>>>表示.它将32位数字中的全部数字总体右移.
注意:
a.无符号右移运算用0填充全部空位.
b.对于整数,无符号右移和有符号右移结果同样.
c.对于负数,因为左侧补0,致使负数通过无符号右移后,变为一个正数
例如:
document.write(-10>>>1);
结果:
运算过程:
-10
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 通过无符号右移-10>>>1
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
结果:
2147483643