計(jì)算機(jī)中的數(shù)在內(nèi)存中都是以二進(jìn)制形式進(jìn)行存儲的蟹漓,用位運(yùn)算就是直接對整數(shù)在內(nèi)存中的二進(jìn)制位進(jìn)行操作棉圈,因此其執(zhí)行效率非常高实苞,在程序中盡量使用位運(yùn)算進(jìn)行操作剪廉,這會大大提高程序的性能烈涮。
位操作符
& 與運(yùn)算 兩個(gè)位都是 1 時(shí)朴肺,結(jié)果才為 1,否則為 0坚洽,如
1 0 0 1 1
&? 1 1 0 0 1
------------------------------
1 0 0 0 1
| 或運(yùn)算 兩個(gè)位都是 0 時(shí)戈稿,結(jié)果才為 0,否則為 1讶舰,如
1 0 0 1 1
|? 1 1 0 0 1
------------------------------
1 1 0 1 1
^ 異或運(yùn)算鞍盗,兩個(gè)位相同則為 0,不同則為 1跳昼,如
1 0 0 1 1
^? 1 1 0 0 1
-----------------------------
0 1 0 1 0
~ 取反運(yùn)算般甲,0 則變?yōu)?1,1 則變?yōu)?0鹅颊,如
~? 1 0 0 1 1
-----------------------------
0 1 1 0 0
?
<< 左移運(yùn)算敷存,向左進(jìn)行移位操作,高位丟棄堪伍,低位補(bǔ) 0历帚,如
int a = 8;
a << 3;
移位前:0000 0000 0000 0000 0000 0000 0000 1000
移位后:0000 0000 0000 0000 0000 0000 0100 0000
>> 右移運(yùn)算,向右進(jìn)行移位操作杠娱,對無符號數(shù)挽牢,高位補(bǔ) 0,對于有符號數(shù)摊求,高位補(bǔ)符號位禽拔,如
unsigned int a = 8;
a >> 3;
移位前:0000 0000 0000 0000 0000 0000 0000 1000
移位后:0000 0000 0000 0000 0000 0000 0000 0001
?
int a = -8;
a >> 3;
移位前:1111 1111 1111 1111 1111 1111 1111 1000
移位前:1111 1111 1111 1111 1111 1111 1111 1111
我們可能很少在編程中用位運(yùn)算,如果沒深入學(xué)習(xí),可能也很難理解睹栖。平時(shí)的數(shù)值運(yùn)算硫惕,其實(shí)是要先轉(zhuǎn)換成二進(jìn)制再進(jìn)行運(yùn)算的,而位運(yùn)算就是直接進(jìn)行二進(jìn)制運(yùn)算野来,所以位運(yùn)算的執(zhí)行效率肯定是更高的恼除。下面通過一些實(shí)例來加深對位運(yùn)算的理解。
按位與(&)
&&運(yùn)算符我們都知道曼氛,只有兩個(gè)都為真豁辉,結(jié)果才為真。&道理是一樣的舀患,只有兩個(gè)數(shù)的值為1時(shí)徽级,才返回1。例如1和3的按位與操作:
0001&0011---------0001
只有對應(yīng)的數(shù)為1時(shí)聊浅,結(jié)果才為1餐抢,其他都為0。
判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù)低匙,我們會用求余數(shù)來判斷:
functionassert(n){if(n %2===1) {? ? console.log("n是奇數(shù)");? ? }else{? ? console.log("n是偶數(shù)");? }}assert(3); //"n是奇數(shù)"
我們也可以用一個(gè)數(shù)和1進(jìn)行按位&操作來判斷旷痕,而且速度更快:
functionassert(n){if(n &1) {? ? console.log("n是奇數(shù)");}else{? ? console.log("n是偶數(shù)");}}assert(3); //"n是奇數(shù)"
下面是位運(yùn)算過程:
1=00013=0011--------& =0001
奇數(shù)的二進(jìn)制碼的最后一位數(shù)肯定是1,而1只有最后一位為1顽冶,按位&操作之后欺抗,結(jié)果肯定只有最后一位數(shù)為1。而偶數(shù)的二進(jìn)制表示的最后一位數(shù)是0渗稍,和1進(jìn)行按位&操作佩迟,結(jié)果所有位數(shù)都為0团滥。
按位或(|)
|與||操作符的道理也是一樣的竿屹,只要兩個(gè)數(shù)中有一個(gè)數(shù)為1,結(jié)果就為1灸姊,其他則為0拱燃。
0001|0011---------0011
對浮點(diǎn)數(shù)向下求整,我們會用下面的方法:
varnum =Math.floor(1.1);// 1
我們也可以用位運(yùn)算來求整:
varnum=1.1|0;// 1
其實(shí)浮點(diǎn)數(shù)是不支持位運(yùn)算的力惯,所以會先把1.1轉(zhuǎn)成整數(shù)1再進(jìn)行位運(yùn)算碗誉,就好像是對浮點(diǎn)數(shù)向下求整。所以1|0的結(jié)果就是1父晶。
按位非(~)
按位非就是求二進(jìn)制的反碼:
varnum=1;// 二進(jìn)制 00000000000000000000000000000001varnum1 = ~num;// 二進(jìn)制 11111111111111111111111111111110
我們知道哮缺,js中的數(shù)字默認(rèn)是有符號的。有符號的32位二進(jìn)制的最高位也就是第一位數(shù)字代表著正負(fù)甲喝,1代表負(fù)數(shù)尝苇,0代表整數(shù)。那到底11111111111111111111111111111110等于多少呢?最高位為1代表負(fù)數(shù)糠溜,負(fù)數(shù)的二進(jìn)制轉(zhuǎn)化為十進(jìn)制:符號位不變淳玩,其他位取反加1。取反之后為10000000000000000000000000000001非竿,加1之后為10000000000000000000000000000010蜕着,十進(jìn)制為-2。
按位異或(^)
按位異或是兩個(gè)數(shù)中只有一個(gè)1時(shí)返回1红柱,其他情況返回0承匣。
0001^0011---------0010
數(shù)字與數(shù)字本身按位異或操作得到的是0,因?yàn)槊績蓚€(gè)對應(yīng)的數(shù)字都相同豹芯,所以最后返回的都是0悄雅。
我們經(jīng)常會需要調(diào)換兩個(gè)數(shù)字的值:
var num1 = 1, num2 = 2, temp;
temp = num1;
num1 = num2; // 2
num2 = temp; // 1
如果裝逼一點(diǎn)的話,可以這樣:
var num1 = 1, num2 = 2;num1 = [num2, num2 = num1][0];console.log(num1); // 2console.log(num2); // 1
如果想再裝的穩(wěn)一點(diǎn)的話铁蹈,可以這樣:
varnum1 =1, num2 =2;num1 ^= num2;// num1 = num1 ^ num2 = 1 ^ 2 = 3num2 ^= num1;// num2 = num2 ^ (num1 ^ num2) = 2 ^ (1 ^ 2) = 1num1 ^= num2;// num1 = num1 ^ num2 = 3 ^ 1 = 2console.log(num1);// 2console.log(num2);// 1
有符號左移(<<)
有符號左移會將32位二進(jìn)制數(shù)的所有位向左移動(dòng)指定位數(shù)宽闲。如:
varnum=2;// 二進(jìn)制10num=num<<5;// 二進(jìn)制1000000,十進(jìn)制64
如果要求2的n次方握牧,可以這樣:
functionpower(n){return1<< n;}power(5);// 32
1的二進(jìn)制是01容诬,左移5位就是0100000,十進(jìn)制就是2的5次方32沿腰。
有符號右移(>>)
有符號右移會將32位二進(jìn)制數(shù)的所有位向右移動(dòng)指定位數(shù)览徒。如:
varnum=64;// 二進(jìn)制1000000num=num>>5;// 二進(jìn)制10,十進(jìn)制2
求一個(gè)數(shù)的二分之一:
var num =64>> 1;//32
有符號左移與右移不會影響符號位颂龙。
無符號右移(>>>)
正數(shù)的無符號右移與有符號右移結(jié)果是一樣的习蓬。負(fù)數(shù)的無符號右移會把符號位也一起移動(dòng),而且無符號右移會把負(fù)數(shù)的二進(jìn)制碼當(dāng)成正數(shù)的二進(jìn)制碼:
varnum=-64;// 11111111111111111111111111000000num=num>>>5;// 134217726
所以措嵌,我們可以利用無符號右移來判斷一個(gè)數(shù)的正負(fù):
functionisPos(n){return(n === (n >>>0)) ?true:false;? ? }isPos(-1);// falseisPos(1);// true
-1>>>0雖然沒有向右移動(dòng)位數(shù)躲叼,但-1的二進(jìn)制碼已經(jīng)變成了正數(shù)的二進(jìn)制碼:
11111111111111111111111111111111
所以-1>>>0的值為4294967295。
~~用來取整
~~3.5? ? 3
~~-2.6? ?-2