老生常談的代碼優(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)你的思考能力。希望能有所幫助。
來自一個矯情的程序員;