《位運算》 的一點理解和運用

老生常談的代碼優(yōu)化

在開發(fā)的過程中,最開始想的是如何完成任務(wù),后來就總想著寫一些 new bee 的代碼,再往后我們可能就該注重性能優(yōu)化了,因為邁出初級程序員的那道坎 已經(jīng)讓你不能再安逸下去了。其中優(yōu)化的手段有很多,從資源的加載到程序的優(yōu)化再到渲染的優(yōu)化;諸如這些,咳咳,我們這里暫且都不談,主要是根據(jù)最近的一些理解,聊一聊代碼中的------位運算。

現(xiàn)在編程語言的更新和進(jìn)步已經(jīng)讓很多的人都不再對內(nèi)存的分配使用花太多的心思了,我們也很少使用匯編語言和VC來進(jìn)行日常開發(fā)了,但是我們都知道,在程序中的所有的數(shù) 在計算機(jī)的內(nèi)存中都是以二進(jìn)制的形式存儲的,而我們今天要談的位運算就是直接對內(nèi)存中的二進(jìn)制位進(jìn)行操作;廢話不多說,上表:


運算符號

注意首先操作對象都是整數(shù)類型

1、按位與? &?

按位與 運算通常用于二進(jìn)制的取位操作,例如 一個數(shù) & 1 的結(jié)果就是取其二進(jìn)制的最末位,有什么實際意義呢?對了,這可以用來判斷一個整數(shù)的奇偶!二進(jìn)制的最末位為0表示該數(shù)為偶數(shù),最末位為1表示該數(shù)為奇數(shù)。相同位的兩個數(shù)字都為1,則為1;若有一個不為1,則為0。我們在日常開發(fā)中經(jīng)常會有需求來判斷序列奇數(shù)位和偶數(shù)位的表現(xiàn)形式或者功能不一樣,這樣就好了? 直接? ?&1? ,底層操作,代碼簡潔,是不是甩那些 ”? %2? == 0 “的程序員十八條街?


2、 按位或? |

按位或?運算通常用于二進(jìn)制特定位上的無條件賦值,例如一個數(shù)or 1的結(jié)果就是把二進(jìn)制最末位強(qiáng)行變成1。如果需要把二進(jìn)制最末位變成0,對這個數(shù)or 1之后再減一就可以了,其實際意義就是把這個數(shù)強(qiáng)行變成最接近的偶數(shù)。相同位上只要有一個1 即為1; 這個需求可以了解,日常使用的話 可能略顯浮夸;容易被吐槽。


3、 異或? ^

異或的符號是 ^ 。按位異或運算, 對等長二進(jìn)制模式按位或二進(jìn)制數(shù)的每一位執(zhí)行邏輯按位異或操作. 操作的結(jié)果是如果某位不同則該位為1, 否則該位為0.按位異或運算的逆運算是它本身,也就是說兩次異或同一個數(shù)最后結(jié)果不變,即(a ^ b) ^ b = a。按位異或運算可以用于簡單的加密,舉一個容易理解的例子:比如我想對一個后端MM說1314520,但怕別人知道,于是雙方約定拿我的生日19941104作為密鑰。1314520 ^ 19941104 = 19154984,我就把19154984告訴MM。MM再次計算19154984 ^ 19941104的值,得到1314520。這樣 就可以提前祝你成功了!什么成功。呃呃 ,你們的數(shù)字就都可以加密了,這里涉及到具體的東西,比如傳輸金幣的數(shù)值,體力的數(shù)值,等等,反正早晚會用到的吧。。。

再有一個常用的功能,我們經(jīng)常用到的功能,是每一個程序員閉著眼都應(yīng)該寫出來的功能,swap.沒錯,在這里解釋一下swap,知道的可以跳過,swap就是交換分區(qū),上一段偽代碼就知道了;

```

temp = a;

a = b;

b = temp;

```

是不是很眼熟?說到這里就再談?wù)?,有時候不想分配一個多余的變量,我們會這樣操作;

```

a = a + b;

b = a - b;

a = a - b;

```

好吧,我承認(rèn)你要是在學(xué)校,老師肯定會夸你,這位同學(xué)不錯,理解的很快;僅限學(xué)校哈;那么接下來,看一點很厲害的東西。。。。

```

a = a ^ b;

b = a ^ b;

a = a ^ b;

```

是不是很詭異呢?是剛才你說的 ^ 逆運算是本身嘛,這么寫完全沒問題,所以,可以拿去裝X 了。


4、按位取反運算? ~

敲黑板,這里不是析構(gòu)函數(shù),這里是位運算帶你裝X帶你飛課堂,哈哈;按位取反運算的定義是把內(nèi)存中的0和1全部取反。計算方法是這樣的,

1、將待計算的數(shù)用2進(jìn)制表示,位數(shù)最少為可以表示出當(dāng)前數(shù)的絕對值的二進(jìn)制位數(shù)加1(多1位符號位)。也就是將9表示為01001,其中最左面的0是符號位,0為正,1為負(fù)。

2、將每個二進(jìn)制位取反,及如果是1,結(jié)果為0,反之結(jié)果為1。取反后結(jié)果為10110

3、將結(jié)果看做是有符號數(shù),轉(zhuǎn)為十進(jìn)制即可。最左面的一位是符號位,1代表是負(fù)的。在計算機(jī)中負(fù)數(shù)是補(bǔ)碼表示的,有符號數(shù)10110轉(zhuǎn)為10進(jìn)制即-10。

計算按位取反的簡便算法:? ?用 -1 減去待取反的數(shù)即為按位取反的結(jié)果:-1-9=-10。而,這個在實際操作中有什么用呢()?看這里,舉一個例子,有時我們會判斷一個字符串中是否存在已有的字符串,(栗子要廣義的理解,不要過分糾結(jié)偽代碼的真假)

`return? this.systemInfo['system'].indexOf('ios')? !=? -1 ;` ,我們會通過它返回的值來判斷是否是iOS設(shè)備,一般人會這么寫 ,如果上面的代碼返回 -1? 即不是iOS,反之為是;那么看下面的代碼;

`return? !!( ~ this.systemInfo['system'].indexOf('ios')) ;`

是不是瞬間高大上了,而且注意,這種位運算更快,更節(jié)省性能;

(? ? ?!!? ? ? 的功能是把 null 、undefined 、0 都變成 false? ,平時用的少的可能不知道)


5、左移運算; <<?

a << b就表示把a(bǔ)轉(zhuǎn)為二進(jìn)制后左移b位(在后面添b個0)。例如100的二進(jìn)制為1100100,而110010000轉(zhuǎn)成十進(jìn)制是400,那么100 << 2 = 400??梢钥闯?,a << b的值實際上就是a乘以2的b次方,因為在二進(jìn)制數(shù)后添一個0就相當(dāng)于該數(shù)乘以2。

通常認(rèn)為a << 1比 a * 2更快,因為前者是更底層一些的操作。因此程序中乘以2的操作請盡量用左移一位來代替。


6、右移運算; >>

和左移相似,a >>?b表示二進(jìn)制右移b位(去掉末b位),相當(dāng)于a除以2的b次方(取整)。和上面一樣的例子,那么400 >> 2 = 100。我們也經(jīng)常用 >> 1來代替 / 2,比如二分查找、堆的插入操作等等。想辦法用 >> 代替除法運算可以使程序效率大大提高。最大公約數(shù)的二進(jìn)制算法用除以2操作來代替mod運算,效率可以提高60%。(這是百度百科上說的,不是我說的。)

這一點在日常代碼中應(yīng)用就更多了,比如我們設(shè)置圖形的錨點的時候;

```

img.anchorOffsetX = img.width >> 1;

img.anchorOffsetY = img.height >> 1;

```

這樣的代碼簡潔、規(guī)范、還高效,何樂而不為呢?

好了,都說完了,或許這些都是技術(shù)大牛不屑一顧的,但是對于我這種小學(xué)生來說,以后還是要掌握并且熟練使用的,最起碼,不想吃天鵝肉的癩蛤蟆不是好癩蛤蟆,哈哈,做技術(shù)不能只為了完成需求,要多更多的理解,想別人想不到的東西,開始想的淺沒關(guān)系,只要養(yǎng)成了思考的習(xí)慣,當(dāng)你有一天回首的時候,你就會發(fā)現(xiàn)自己已經(jīng)到達(dá)了一個很高的高度,至少會欣慰一些吧,前兩天看到一個985碩士,13年工作經(jīng)驗,被一個公司的HR開價2800一個月.我不知道他怎么想的,或許這不是真的故事,但至少我們別在30歲還是個初級程序員的水平就好了;

以后面對如何進(jìn)行優(yōu)化的面試題,是不是又多了一條代碼優(yōu)化的回答呢?這個回答可能是雕蟲小計,但是很能反應(yīng)你的思考能力。希望能有所幫助。

來自一個矯情的程序員;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容