• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            面對(duì)現(xiàn)實(shí),超越自己
            逆水行舟,不進(jìn)則退
            posts - 269,comments - 32,trackbacks - 0

            說(shuō)說(shuō)異或運(yùn)算^和他的一個(gè)常用作用。
            異或的運(yùn)算方法是一個(gè)二進(jìn)制運(yùn)算:
            1^1=0
            0^0=0
            1^0=1
            0^1=1

            兩者相等為0,不等為1.

            這樣我們發(fā)現(xiàn)交換兩個(gè)整數(shù)的值時(shí)可以不用第三個(gè)參數(shù)。
            如a=11,b=9.以下是二進(jìn)制
            a=a^b=1011^1001=0010;
            b=b^a=1001^0010=1011;
            a=a^b=0010^1011=1001;
            這樣一來(lái)a=9,b=13了。


            舉一個(gè)運(yùn)用, 按一個(gè)按鈕交換兩個(gè)mc的位置可以這樣。

            mybt.onPress=function()
            {
            mc1._x=mc1._x^mc2._x;
            mc2._x=mc2._x^mc1._x;
            mc1._x=mc1._x^mc2._x;
            //
            mc1._y=mc1._y^mc2._y;
            mc2._y=mc2._y^mc1._y;
            mc1._y=mc1._y^mc2._y;
            }

            這樣就可以不通過(guò)監(jiān)時(shí)變量來(lái)傳遞了。

            最后要聲明:只能用于整數(shù)。

             

            1. 位運(yùn)算 請(qǐng)點(diǎn)評(píng)

            整數(shù)在計(jì)算機(jī)中用二進(jìn)制的位來(lái)表示,C語(yǔ)言提供一些運(yùn)算符可以直接操作整數(shù)中的位,稱為位運(yùn)算,這些運(yùn)算符的操作數(shù)都必須是整型的。在以后的學(xué)習(xí)中你會(huì)發(fā)現(xiàn),有些信息利用整數(shù)中的某幾個(gè)位來(lái)存儲(chǔ),要訪問(wèn)這些位,僅僅有對(duì)整數(shù)的操作是不夠的,必須借助位運(yùn)算,例如第 2 節(jié) “Unicode和UTF-8” 介紹的UTF-8編碼就是如此,學(xué)完本節(jié)之后你應(yīng)該能自己寫出UTF-8的編碼和解碼程序。本節(jié)首先介紹各種位運(yùn)算符,然后介紹與位運(yùn)算有關(guān)的編程技巧。

            1.1. 按位與、或、異或、取反運(yùn)算 請(qǐng)點(diǎn)評(píng)

            第 3 節(jié) “布爾代數(shù)” 講過(guò)邏輯與、或、非運(yùn)算,并列出了真值表,對(duì)于整數(shù)中的位也可以做與、或、非運(yùn)算,C語(yǔ)言提供了按位與(Bitwise AND)運(yùn)算符&、按位或(Bitwise OR)運(yùn)算符|和按位取反(Bitwise NOT)運(yùn)算符~,此外還有按位異或(Bitwise XOR)運(yùn)算符^,我們?cè)?a style="color: #336699; text-decoration: initial;">第 1 節(jié) “為什么計(jì)算機(jī)用二進(jìn)制計(jì)數(shù)” 講過(guò)異或運(yùn)算。下面用二進(jìn)制的形式舉幾個(gè)例子。

            圖 16.1. 位運(yùn)算

            位運(yùn)算

            注 意,&、|、^運(yùn)算符都是要做Usual Arithmetic Conversion的(其中有一步是Integer Promotion),~運(yùn)算符也要做Integer Promotion,所以在C語(yǔ)言中其實(shí)并不存在8位整數(shù)的位運(yùn)算,操作數(shù)在做位運(yùn)算之前都至少被提升為int 型了,上面用8位整數(shù)舉例只是為了書寫方便。比如:

            unsigned char c = 0xfc;
            unsigned int i = ~c;

            計(jì)算過(guò)程是這樣的:常量0xfc是int 型的,賦給c 要轉(zhuǎn)成unsigned char ,值不變;c 的十六進(jìn)制表示是fc,計(jì)算~c 時(shí)先提升為整型(000000fc)然后取反,最后結(jié)果是ffffff03。注意,如果把~c 看成是8位整數(shù)的取反,最后結(jié)果就得3了,這就錯(cuò)了。為了避免出錯(cuò),一是盡量避免不同類型之間的賦值,二是每一步計(jì)算都要按上一章講的類型轉(zhuǎn)換規(guī)則仔細(xì)檢查。

            1.2. 移位運(yùn)算 請(qǐng)點(diǎn)評(píng)

            移位運(yùn)算符(Bitwise Shift)包括左移<<和右移>>。左移將一個(gè)整數(shù)的各二進(jìn)制位全部左移若干位,例如0xcfffffff3<<2得到0x3fffffcc:

            圖 16.2. 左移運(yùn)算

            左移運(yùn)算

            最高兩位的11被移出去了,最低兩位又補(bǔ)了兩個(gè)0,其它位依次左移兩位。但要注意,移動(dòng)的位數(shù)必須小于左操作數(shù)的總位數(shù),比如上面的例子,左邊是unsigned int 型,如果左移的位數(shù)大于等于32位,則結(jié)果是Undefined。移位運(yùn)算符不同于+ - * / ==等運(yùn)算符,兩邊操作數(shù)的類型不要求一致,但兩邊操作數(shù)都要做Integer Promotion,整個(gè)表達(dá)式的類型和左操作數(shù)提升后的類型相同。

            復(fù)習(xí)一下第 2 節(jié) “不同進(jìn)制之間的換算” 講過(guò)的知識(shí)可以得出結(jié)論,在一定的取值范圍內(nèi),將一個(gè)整數(shù)左移1位相當(dāng)于乘以2 。比如二進(jìn)制11(十進(jìn)制3)左移一位變成110,就是6,再左移一位變成1100,就是12。讀者可以自己驗(yàn)證這條規(guī)律對(duì)有符號(hào)數(shù)和無(wú)符號(hào)數(shù)都成立,對(duì)負(fù)數(shù)也成立。當(dāng)然,如果左移改變了最高位(符號(hào)位),那么結(jié)果肯定不是乘以2了,所以我加了個(gè)前提“在一定的取值范圍內(nèi) ”。由于計(jì)算機(jī)做移位比做乘法快得多,編譯器可以利用這一點(diǎn)做優(yōu)化,比如看到源代碼中有i * 8 ,可以編譯成移位指令而不是乘法指令。

            當(dāng)操作數(shù)是無(wú)符號(hào)數(shù)時(shí),右移運(yùn)算的規(guī)則和左移類似,例如0xcfffffff3>>2得到0x33fffffc:

            圖 16.3. 右移運(yùn)算

            右移運(yùn)算

            最低兩位的11被移出去了,最高兩位又補(bǔ)了兩個(gè)0,其它位依次右移兩位。和左移類似,移動(dòng)的位數(shù)也必須小于左操作數(shù)的總位數(shù),否則結(jié)果是Undefined。在一定的取值范圍內(nèi),將一個(gè)整數(shù)右移1位相當(dāng)于除以2,小數(shù)部分截掉。

            當(dāng)操作數(shù)是有符號(hào)數(shù)時(shí),右移運(yùn)算的規(guī)則比較復(fù)雜:

            • 如果是正數(shù),那么高位移入0

            • 如果是負(fù)數(shù),那么高位移入1還是0不一定,這是Implementation-defined的。對(duì)于x86平臺(tái)的gcc 編譯器,最高位移入1,也就是仍保持負(fù)數(shù)的符號(hào)位,這種處理方式對(duì)負(fù)數(shù)仍然保持了“右移1位相當(dāng)于除以2 ”的性質(zhì)。

            綜上所述,由于類型轉(zhuǎn)換和移位等問(wèn)題,用有符號(hào)數(shù)做位運(yùn)算是很不方便的,所以,建議只對(duì)無(wú)符號(hào)數(shù)做位運(yùn)算,以減少出錯(cuò)的可能 。

            1、下面兩行printf 打印的結(jié)果有何不同?請(qǐng)讀者比較分析一下。%x 轉(zhuǎn)換說(shuō)明的含義詳見(jiàn)第 2.9 節(jié) “格式化I/O函數(shù)” 。

            int i = 0xcffffff3;
            printf("%x/n", 0xcffffff3>>2);
            printf("%x/n", i>>2);

            如果要對(duì)一個(gè)整數(shù)中的某些位進(jìn)行操作,怎樣表示這些位在整數(shù)中的位置呢?可以用掩碼(Mask)來(lái)表示。比如掩碼0x0000ff00表示對(duì)一個(gè)32位整數(shù)的8~15位進(jìn)行操作,舉例如下。

            1、取出8~15位。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = (a & mask) >> 8; /* 0x00000056 */

            這樣也可以達(dá)到同樣的效果:

            b = (a >> 8) & ~(~0U << 8);

            2、將8~15位清0。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = a & ~mask; /* 0x12340078 */

            3、將8~15位置1。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = a | mask; /* 0x1234ff78 */

            1、統(tǒng)計(jì)一個(gè)無(wú)符號(hào)整數(shù)的二進(jìn)制表示中1的個(gè)數(shù),函數(shù)原型是int countbit(unsigned int x); 。

            2、用位操作實(shí)現(xiàn)無(wú)符號(hào)整數(shù)的乘法運(yùn)算,函數(shù)原型是unsigned int multiply(unsigned int x, unsigned int y); 。例如:(11011)2 ×(10010)2 =((11011)2 <<1)+((11011)2 <<4)。

            3、對(duì)一個(gè)32位無(wú)符號(hào)整數(shù)做循環(huán)右移,函數(shù)原型是unsigned int rotate_right(unsigned int x, int n); 。所謂循環(huán)右移就是把低位移出去的部分再補(bǔ)到高位上去,例如rotate_right(0xdeadbeef, 8) 的值應(yīng)該是0xefdeadbe。

            1.4. 異或運(yùn)算的一些特性 請(qǐng)點(diǎn)評(píng)

            1、一個(gè)數(shù)和自己做異或的結(jié)果是0。如果需要一個(gè)常數(shù)0,x86平臺(tái)的編譯器可能會(huì)生成這樣的指令:xorl %eax, %eax 。不管eax 寄存器里的值原來(lái)是多少,做異或運(yùn)算都能得到0,這條指令比同樣效果的movl $0, %eax 指令快,直接對(duì)寄存器做位運(yùn)算比生成一個(gè)立即數(shù)再傳送到寄存器要快一些。

            2、從異或的真值表可以看出,不管是0還是1,和0做異或保持原值不變,和1做異或得到原值的相反值。可以利用這個(gè)特性配合掩碼實(shí)現(xiàn)某些位的翻轉(zhuǎn),例如:

            unsigned int a, b, mask = 1U << 6;
            a = 0x12345678;
            b = a ^ mask; /* flip the 6th bit */

            3、如果a1 ^ a2 ^ a3 ^ ... ^ an 的結(jié)果是1,則表示a1 、a2 、a3 ...an 之中1的個(gè)數(shù)為奇數(shù)個(gè),否則為偶數(shù)個(gè)。這條性質(zhì)可用于奇偶校驗(yàn)(Parity Check),比如在串口通信過(guò)程中,每個(gè)字節(jié)的數(shù)據(jù)都計(jì)算一個(gè)校驗(yàn)位,數(shù)據(jù)和校驗(yàn)位一起發(fā)送出去,這樣接收方可以根據(jù)校驗(yàn)位粗略地判斷接收到的數(shù)據(jù)是否有誤。

            4、x ^ x ^ y == y,因?yàn)閤 ^ x == 0,0 ^ y == y。這個(gè)性質(zhì)有什么用呢?我們來(lái)看這樣一個(gè)問(wèn)題:交換兩個(gè)變量的值,不得借助額外的存儲(chǔ)空間,所以就不能采用temp = a; a = b; b = temp; 的辦法了。利用位運(yùn)算可以這樣做交換:

            a = a ^ b;
            b = b ^ a;
            a = a ^ b;

            分析一下這個(gè)過(guò)程。為了避免混淆,把a(bǔ)和b的初值分別記為a0 和b0 。第一行,a = a0 ^ b0 ;第二行,把a(bǔ)的新值代入,得到b = b0 ^ a0 ^ b0 ,等號(hào)右邊的b0 相當(dāng)于上面公式中的x,a0 相當(dāng)于y,所以結(jié)果為a0 ;第三行,把a(bǔ)和b的新值代入,得到a = a0 ^ b0 ^ a0 ,結(jié)果為b0 。注意這個(gè)過(guò)程不能把同一個(gè)變量自己跟自己交換,而利用中間變量temp 則可以交換。

            1、請(qǐng)?jiān)诰W(wǎng)上查找有關(guān)RAID(Redundant Array of Independent Disks,獨(dú)立磁盤冗余陣列)的資料,理解其實(shí)現(xiàn)原理,其實(shí)就是利用了本節(jié)的性質(zhì)3和4。

            2、交換兩個(gè)變量的值,不得借助額外的存儲(chǔ)空間,除了本節(jié)講的方法之外你還能想出什么方法?本節(jié)講的方法不能把同一個(gè)變量自己跟自己交換,你的方法有沒(méi)有什么局限性?

            本文轉(zhuǎn)自:http://blog.csdn.net/yunyuehu/article/details/5408446#t1

            posted on 2013-01-18 11:07 王海光 閱讀(930) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++
            无码国内精品久久综合88| 国产成年无码久久久免费| 久久国产综合精品五月天| 久久亚洲av无码精品浪潮| 99久久香蕉国产线看观香| 99久久婷婷国产综合亚洲| 国产精品久久久99| 亚洲AV成人无码久久精品老人| 国产精品99久久精品| 久久亚洲日韩看片无码| 久久久青草青青亚洲国产免观| 久久av高潮av无码av喷吹| 亚洲人成精品久久久久| 国产精品热久久毛片| 无码精品久久久天天影视 | 久久综合狠狠综合久久激情 | 蜜桃麻豆www久久| 久久精品国产乱子伦| 亚洲国产精品久久久久婷婷软件 | 精品久久久久中文字| 国产精品美女久久久m| 区亚洲欧美一级久久精品亚洲精品成人网久久久久| 国产69精品久久久久9999APGF| 久久影院午夜理论片无码| 97久久精品人人做人人爽| 精品免费久久久久久久| 色婷婷综合久久久久中文一区二区| 欧洲国产伦久久久久久久| 精品国产青草久久久久福利| 久久综合九色综合97_久久久| 久久99热只有频精品8| 久久精品国产亚洲AV嫖农村妇女| 亚洲欧美一区二区三区久久| 人妻系列无码专区久久五月天| 777久久精品一区二区三区无码| 久久精品草草草| 一本久久久久久久| 国产成人精品久久亚洲高清不卡| 99久久99久久精品国产片果冻| 99久久精品免费看国产| 久久成人18免费网站|