欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript 二進(jìn)制運算技巧解析

 更新時間:2012年11月27日 10:14:36   作者:  
javascript 中的二進(jìn)制運算的一些技巧,曬出來和你們分享一下,希望可以幫助你們
1、原碼、反碼、補碼,正數(shù)減法轉(zhuǎn)補碼加法
js 在進(jìn)行二進(jìn)制運算時,使用 32 位二進(jìn)制整數(shù),由于 js 的整數(shù)都是有符號數(shù),最高位0表示正數(shù),1表示負(fù)數(shù),因此,js 二進(jìn)制運算中使用的整數(shù)表達(dá)范圍是
復(fù)制代碼 代碼如下:

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

原碼:最高位 0 表示正,1表示負(fù),其余 31 位是該數(shù)的絕對值(真值的絕對值)的二進(jìn)制形式
反碼:正數(shù)反碼與原碼相同,負(fù)數(shù)反碼是原碼符號位不變,其余31位取反(0變1,1變0)
補碼:正數(shù)補碼與原碼相同,負(fù)數(shù)補碼為反碼加 1 (符號位參與運算,其實只有求 -0 的補碼才涉及最高位進(jìn)位,因此不用擔(dān)心在反碼加1時由于符號位參與運算進(jìn)位而使 - 變 +)。
+0 的反碼:32個0 ,按正數(shù)處理,原碼、反碼、補碼都是0。
-0 的反碼:最高位1,其余位由 +0 原碼取反,得到 32 個 1
-0 的補碼:其反碼是 32 個 1 加 1,最高位溢出被舍棄,得到 32 個0
因此,正負(fù) 0 的補碼都是 0.
由負(fù)數(shù)的補碼求他的絕對值補碼:負(fù)二進(jìn)制數(shù)的絕對值,只要各位(包括符號位)取反,再加1,就得到其絕對值。
計算機在處理加減運算時,使用補碼進(jìn)行運算,減法被視為加上一個負(fù)數(shù),在處理負(fù)數(shù)時,用負(fù)數(shù)的補碼進(jìn)行加法可以即可得到正確運算結(jié)果,補碼是為了統(tǒng)一加減運算而生的。
正數(shù)減法轉(zhuǎn)補碼加法的原理是 32 位數(shù)溢出:
對于32 位二進(jìn)制正整數(shù)來說,其模為
復(fù)制代碼 代碼如下:

Math.pow(2,32) = 4294967296

32 位正整數(shù)最大表達(dá)范圍是 4294967296 - 1 ,達(dá)到 4294967296 這個值就要進(jìn)位到33位,33 位是溢出位被丟棄,只得到32 個0(這個道理跟表盤上 0 點 和12 點的時針指在同一個位置是一樣的,表盤以 12 為模),因此,一個數(shù)逐漸增大,一旦超出 4294967296-1 的數(shù) M 就可以表示為 M%4294967296
而負(fù)數(shù) -M (M為絕對值)可以表示為一個正數(shù): 4294967296 - M(這個正數(shù)就是負(fù)數(shù)的補碼對應(yīng)的二進(jìn)制正整數(shù),負(fù)數(shù)的補碼按32位二進(jìn)制數(shù),與他的原碼相加剛好等于模 ),道理跟表盤一樣,11點和負(fù)1點指在同一個位置。
以 -3 為例:
復(fù)制代碼 代碼如下:

(Array(32).join("0")+(3).toString(2)).slice(-32); // |-3| 的二進(jìn)制數(shù),即原碼
原碼 = 00000000000000000000000000000011;
反碼 = 11111111111111111111111111111100; //原碼符號位為1,其余位取反
補碼 = 11111111111111111111111111111101; //反碼加1因為反碼由正數(shù)形式的原碼低31位取反得到,因此這兩個數(shù)的低31位全都是1,加上反碼符號位1,得到32 個1
那么,有
補碼+原碼 = (反碼+1)+原碼
= (反碼+原碼)+1
= 1+(32位全是 1 的二進(jìn)制數(shù)) //因為反碼由正數(shù)形式的原碼的低31位取反加上符號位1得到,因此這兩個數(shù)的和的低31位全都是1,加上反碼符號位1,得到32 個1
= Math.pow(2,32)
= 4294967296 //這正是32位二進(jìn)制數(shù)的模, 跟 |-1|+11 = 12 原理一樣

這就是: 正數(shù)減法 -> 負(fù)數(shù)加法 -> 補碼加法 的過程。
2、位運算
因為 js 的整數(shù)默認(rèn)是帶符號正數(shù),所以在為運算中,只能使用 31 位,開發(fā)者是不能訪問最高位的。
位運算只發(fā)生在整數(shù)上,因此一個非浮點數(shù)參與位運算之前會被向下取整。
為了避免訪問符號位, javascript 在現(xiàn)實 負(fù)數(shù)的 二進(jìn)制時,轉(zhuǎn)換為 符號及 其絕對值的二進(jìn)制,如:
復(fù)制代碼 代碼如下:

(-123).toString(2) ;// "-1111011"

按位取反(~): 一元運算, 1 變0,0變1 ,如
~123 ; //-124
可以驗證一下這個過程:正數(shù)取反,符號位為負(fù),所以結(jié)果是一個負(fù)數(shù),根據(jù) Math.pow(2,32) - M 可以表示成 -M,可以按下面方法計算
復(fù)制代碼 代碼如下:

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 ,如果是負(fù)數(shù)減 Math.pow(2,32)

需要注意的是, javascript 位運算都是有符號的,因此達(dá)到 32 位,其最高位將作為 符號位,取反時應(yīng)得到正數(shù)(取模 Math.pow(2,32) 的補數(shù)--兩個數(shù)相加得到模,稱這兩個數(shù)互為補數(shù))。
對整數(shù) M 按位取反可以這樣算:
復(fù)制代碼 代碼如下:

((-1*M-1)+Math.pow(2,32))%Math.pow(2,32)

按位與(&):兩個數(shù)的相同位,都是 1 返回1 ,否則返回0
復(fù)制代碼 代碼如下:

&234 = 106
"00000000000000000000000001111011"
"00000000000000000000000011101010"
---------------------------------------------
"00000000000000000000000001101010"

復(fù)制代碼 代碼如下:

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

按位異或(^):兩個數(shù)的相同位,一個是 1 另一個是 0 則返回 1,否則返回0
復(fù)制代碼 代碼如下:

^234 = 145
"00000000000000000000000001111011"
"00000000000000000000000011101010"
---------------------------------------------
"00000000000000000000000010010001"

異或運算的一些特性:
復(fù)制代碼 代碼如下:

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 //這個特性被用在一些加密算法中
//如果運算數(shù)在適當(dāng)范圍內(nèi)(不溢出), 如 a=1,b=2,交換兩個變量的值
a = [b,b=a][0]
//或者
a = a^b
b = a^b
a= a^b

利用位的異或運算使用一個數(shù)字記錄多個信息:
有幾個狀態(tài)值分別是 1、2、8、16 .....
這些值的規(guī)律是,他們的二進(jìn)制只有一位是 1 ,其余都是 0, 因此, 他們中的任意幾個的按位異或運算的結(jié)果都不會出現(xiàn) 兩個數(shù)的某一位都是 1 的情況,并且運算的值都是唯一確定的,也就是,知道運算的結(jié)果,就知道是哪幾個數(shù)的組合,這樣可以用一個數(shù)字記錄多個信息。
復(fù)制代碼 代碼如下:

00000001
00000010
00000100
00001000
00010000

1^2^4 = 7 // "00000111"
因此,如果我們知道結(jié)果是 7 ,就知道他們是由 1 、2、4 組合而成。
如果我們要設(shè)置一個參數(shù),使其包含幾個狀態(tài)值,就可以用 按位或運算,
這樣的例子可以參考 PHP 中關(guān)于圖片類型的幾個常量,和 PHP 錯誤等級定義的幾個常量。
這樣的例子,也許有用十進(jìn)制數(shù)來描述的,比如: 個位數(shù)的數(shù)字表示某個屬性的狀態(tài),十位數(shù)的數(shù)字表示另一個屬性的狀態(tài),這樣的話,每個狀態(tài)可以有 10 個值,只用一個數(shù)字就可以描述的組合非常多。
左移位(<<) : 一個數(shù)的二進(jìn)制所有位向左移動,符號位不動,高位溢出丟棄,低位補 0
如果不溢出, 左移位的效果是乘以 2。
右移位(>>): 一個數(shù)的二進(jìn)制所有位向右移動,符號位不動,高位補0,低位丟棄
右移位操作的效果是除以 2 并向下取整。
帶符號右移(>>>):移位時符號位跟隨移動,符號位也作為數(shù)值看待,所以,該操作的結(jié)果是 32 位無符號整數(shù),因此負(fù)數(shù)的帶符號右移將產(chǎn)生正整數(shù),正數(shù)的帶符號右移與 無符號右移相同,這是唯一可以操作符號位的運算。
-123>>>1 ;//2147483586
一些要注意的地方
位運算必須是整數(shù),如果運算元不是可用的整數(shù),將取 0 作為運算元
復(fù)制代碼 代碼如下:

~NaN; // 將執(zhí)行 ~0 ,結(jié)果為 -1
~'x'; // -1
'hello'|0; // 0
({})|0 ; //0

位移運算不能移動超過31位,如果試圖移動超過31位,將位數(shù) 對32取模后再移位
123>>32 //實際是 123>>0 (32%32 = 0)
123>>33 //實際是 123>>1
32位帶符號整數(shù)表達(dá)范圍是 -Math.pow(2,31) ~ Math.pow(2,31)-1 即 -2147483648~2147483647,而 js 數(shù)字的精度是雙精度,64位,如果一個超過 2147483647 的整數(shù)參與位運算的時候就需要注意,其二進(jìn)制溢出了,截取32位后,如果第32位是1將被解讀為負(fù)數(shù)(補碼)。
復(fù)制代碼 代碼如下:

>>0; //-2147483648
>>0; //0
>>0; //-1
>>0; //1

相關(guān)文章

最新評論