一、原碼、反碼、補碼,正數減法轉補碼加法
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