青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fly me to the moon

the beauty of C++

位運算之美——用+,-和位運算實現正整數除法和取模(一)

9月21日,對本文從格式到部分內容上都進行了修改
另外,鑒于某些轉載沒有注明出處,考慮到版權問題,特聲明如下:
作者:翼帆@cppblog 
原文地址:http://m.shnenglu.com/xiaoyisnail/archive/2009/09/19/96707.html
本文版權歸作者和cppblog共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

    今天看了一位師兄去年的筆經總結,其中有一題是“不許用%和/來實現求任意數除以3的余數”,我想考官的目的應該是想考察學生對位運算的熟悉程度吧,于是我把題目擴展成“只能用+,-和位運算實現正整數除法(/)和取模(%)”,注意:這里不能使用其它的庫例程來輔助計算,如log,log10等。在思考這道題目的過程中,我又涉及到了許多二進制相關的題目,如:
    判斷給定的整數是不是2的整數次冪
    判斷給定的整數是不是4的整數次冪
    求給定整數的二進制表示中1的個數
    求給定整數的二進制表示中0的個數
    求給定整數的二進制表示中最高位1的位置
    求大于等于給定整數的最小的2的整數次冪
    求給定整數的二進制表示的有效位數
    ...
    9月21日補充:這里只考慮值為正整數的情況。
    這些題目都是經典老題,頻繁出現于各類筆試面試題中,除了能考察位運算外,還能考察應聘者能否給出創新的算法來更好地解決問題。可以說這些題目都不難,如果使用32位的int來表示整數的話,蠻力法都可以比較好地完成任務,但是如果想盡可能地提高效率,那就需要動一番腦經了。下面給出我對這些問題的整理和C++實現,并在下次的文章中給出只用+,-和位運算實現的正整數除法和取模。
    從某種意義上講,特別是從充分利用底層硬件的計算能力(利用特殊的cpu指令)來看,這些解法肯定不是最優的,所以還希望大俠們多多指點。
   
    判斷給定的整數是不是2的整數次冪
    這應該是最簡單的,利用最高位是1,其后所有位為0的特性,常數時間解決問題:

1 //判斷n是否是2的正整數冪
2 inline bool is_2exp(unsigned int n)
3 {
4     return !(n&(n-1));
5 }

    求給定整數的二進制表示中1的個數
    考慮到n-1會把n的二進制表示中最低位的1置0并把其后的所有0置1,同時不改變此位置前的所有位,那么n&(n-1)即可消除這個最低位的1。這樣便有了比順序枚舉所有位更快的算法:循環消除最低位的1,循環次數即所求1的個數。此算法的時間復雜度為O(n的二進制表示中的1的個數),最壞情況下的復雜度O(n的二進制表示的總位數)。
 1//計算n的二進制表示中1的個數
 2inline int count1(unsigned int n)
 3{
 4    int r = 0;
 5    while(n)
 6    {
 7        n &= n-1;
 8        r++;
 9    }

10    return r;
11}
    既然有了求給定整數的二進制表示中1的個數的辦法,那么想要求給定整數的二進制表示中0的個數就很簡單了。事實上,在二進制中,完全可以把0和1看作是對稱的兩個對象,取反操作(~)可以任意的切換這兩個對象,只要先對n進行一次取反,然后再用上述算法即能得到二進制表示中0的個數。首先看下面的代碼:
 1//計算n的二進制表示中0的個數
 2inline int count0_wrong(unsigned int n)
 3{
 4    int r = 0;
 5    n &= ~n;
 6    while(n)
 7    {
 8        n &= n-1;
 9        r++;
10    }

11    return r;
12}
    不知大家有沒有看出問題來?是的,~操作符會把所有高位的都取反,而不是只把有效位取反,所以我們需要一個能保持高位不變的位取反操作,下面是我的實現,時間復雜度和求二進制表示中1的個數的算法相同,都與二進制表示中1的個數有關:
 1//保持高位取反
 2inline unsigned int negate_bits(unsigned int n)
 3{
 4    if(n==0return 1;
 5    unsigned int r=0, m=~n;
 6    while(n)
 7    {
 8        r |= (n^(n-1))&m;
 9        n &= n-1;
10    }

11
12    return r;
13}
    有了這個特殊的取反操作,求給定整數的二進制表示中0的個數的辦法就簡單了:
 1//計算n的二進制表示中0的個數
 2inline int count0( unsigned int n)
 3{
 4    int r = 0;
 5    n = negate_bits(n);
 6    while(n)
 7    {
 8        n &= n-1;
 9        r++;
10    }

11    return r;
12}
    看到這里,聰明的讀者肯定看出問題來了,其實我干了一件很蠢的事情。看看上述算法的時間復雜度,negate_bits花了O(n的二進制表示中1的個數),while循環計算取反后的n的二進制表示中1的個數,事實上就是O(n的二進制表示中0的個數),兩部分加起來其實就是二進制表示總的有效位數,換句話說,這個算法是線性的,而事實上,我們完全可以先線性地求出這個總的有效位數,然后減去1的位數,即得到0的位數,根本不用費那么大勁去整個保持高位的取反操作,兩者的時間復雜度在漸進意義上也是相同的。所以,我犯傻了,但是這里又引出另一個問題:

    求給定整數的二進制表示的有效位數
   
上面提到了線性地求這個位數(下文記為m),即“循環右移1位,記錄右移次數”,時間復雜度O(m)。但是我想,一看到這個題目,所有人的第一反應應該是floor(log2(n))+1吧,但是請注意,本文在一開始就規定了“不能使用庫例程”,那么在這個限制下該怎么做呢?有沒有比線性時間更好的算法呢?其實到目前為止我也沒有什么特別好的算法,希望誰有什么精妙的算法能指點一下,不要打我。。。
 1//求給定整數的二進制表示的位數,線性算法
 2int count_bit(unsigned int n)
 3{
 4    int r = 0;
 5    while(n)
 6    {
 7        n>>=1;
 8        r++;
 9    }

10    return r;
11}

    求大于等于給定整數的最小的2的整數次冪
    首先是最簡單的思路:求出n的二進制表示的總位數m,于是1<<m即為所求值,當然這里要排除n自身就是2的整數次冪的情況,復雜度O(m),實現如下:
 1//求大于等于n的最小的2的正整數冪,方法1
 2//時間復雜度O(n的二進制位長度)
 3unsigned int high_2exp_1(unsigned int n)
 4{
 5    if(n<=1return 1;
 6    if(is_2exp(n)) return n;
 7
 8    unsigned int r = 1;
 9    while(n)
10    {
11        n >>= 1;
12        r <<= 1;
13    }

14
15    return r;
16}
    事實上這就涉及到上面求二進制表示位數的問題,所以目前為止在此基礎上的算法都是線性時間的。   
    那有沒有不用計算位數m,從而效率更好的算法呢,能不能像在計算二進制表示中1的個數時那樣根據1的個數來設計算法呢?回到那一題中,“n-1會把n的二進制表示中最低位的1置0并把其后的所有0置1”,那么n|=n-1就把n的二進制表示中最低位1后的所有0置1,再加上1,那么就把最低位1左移了一位。于是,便有了更好的算法:循環左移最低位的1,直到n是2的整數次冪。該算法跟二進制表示中的1的個數和位置有關,最壞時間復雜度還是O(二進制表示位數),但是比起上一個實現,這個算法在多數情況下都比上一個算法快。實現如下:
 1//求大于等于n的最小的2的正整數冪,方法2
 2//計算時間與n的二進制表示中1的個數和位置有關,比方法1效率高
 3//最壞情況下的時間復雜度與方法1相同
 4unsigned int high_2exp_2(unsigned int n)
 5{
 6    if(n<=1return 1;
 7
 8    while(!is_2exp(n))
 9    {
10        n |= n-1;
11        n++;
12    }

13
14    return n;
15}
    
    最后來一個簡單的擴充題目:
    判斷給定的整數是不是4的整數次冪
    觀察4的整數次冪的特征,容易發現除了滿足n&(n-1)==0外,唯一的1位后的0的個數是偶數,這從4x=22k也能簡單地得到。這就很直觀地衍生出一個簡單的算法:
 1//判斷n是否是4的整數次冪
 2bool is_4exp(unsigned int n)
 3{
 4    if(!is_2exp(n)) return false;
 5
 6    int bit_len = count_bit(n)-1;//線性時間求二進制位數
 7    if((bit_len&0x1)!=1)
 8        return true;
 9    else
10        return false;
11}
    算法很直觀,但是比起is_2exp的常數時間is_4exp的線性時間總讓我覺得不能接受,不過無奈還是沒有想出好辦法來,哎。。。求大牛指點啊
   
    說明:寫這篇文章,已經三次丟失全文了,把我快搞瘋了,firefox下好像有點問題,先把文章發上來,過會兒換到IE下繼續。。。
    再說明:換了IE后就沒再出問題了,不過寫著寫著發現寫了好久,先歇會兒,得看書補習功課了
    最后的說明:下次會給出本文最初提出的問題(只能用+,-和位運算實現正整數除法(/)和取模(%))的實現。

posted on 2009-09-19 13:58 翼帆 閱讀(8325) 評論(3)  編輯 收藏 引用 所屬分類: 算法

評論

# re: 位運算之美——用+,-和位運算實現正整數除法和取模(一)[未登錄] 2010-06-22 16:55 xxx

那么n|=n-1就把n的二進制表示中最低位1后的所有0置1,再加上1,那么就把最低位1左移了一位。

假設n=0x1100,那么n-1 = 0x1011, n | (n - 1) = 0x1111.跟你上面描述不一致.  回復  更多評論   

# re: 位運算之美——用+,-和位運算實現正整數除法和取模(一) 2010-07-31 15:00 myway

總結的不錯  回復  更多評論   

# re: 位運算之美——用+,-和位運算實現正整數除法和取模(一) 2010-11-24 08:07 jingairpi

求給定整數的二進制表示的有效位數

可以binary search最高位置1的位置

int get_leftmost_set_bit(unsigned int n)
{
int l, u, m, t1, t2;

l = 0;
u = sizeof(int) * 8 - 1;
while (l <= u) {
m = l + (u - l)/2;

t1 = n & (~((1 << m) - 1));
t2 = n & (~((1 << (m + 1)) - 1));

if (t1 && !t2) {
return m;
} else if (t1 && t2) {
l = m + 1;
} else {
u = m - 1;
}
}

return -1;
}  回復  更多評論   

導航

<2010年6月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

統計

常用鏈接

留言簿

隨筆分類

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美在线欧美在线| 亚洲国产免费看| 久久久久久免费| 久久精品亚洲一区| 久久久久久久网站| 欧美成人黑人xx视频免费观看| 欧美www在线| 国产精品国产三级国产专播精品人 | 亚洲人成网站色ww在线| 亚洲精品一级| 西西人体一区二区| 欧美成人乱码一区二区三区| 国产精品久久久久久久久免费樱桃 | 欧美在线视频网站| 卡通动漫国产精品| 亚洲精品一品区二品区三品区| 午夜视频久久久久久| 欧美大片在线观看| 国产亚洲欧洲| 正在播放日韩| 麻豆精品视频| 亚洲欧美激情四射在线日| 欧美大胆人体视频| 国产一区自拍视频| 亚洲一级二级在线| 欧美国产日本| 欧美一二三区精品| 欧美少妇一区二区| 亚洲精品中文字幕有码专区| 久久精品免费看| 一区二区三区精密机械公司| 蜜桃av噜噜一区| 国产一区久久久| 亚洲综合三区| 亚洲精品综合在线| 久久综合色影院| 国产一区二区三区自拍| 午夜精品福利视频| 日韩视频一区二区三区在线播放免费观看 | 欧美日韩三区| 亚洲第一黄色网| 久久久噜噜噜久久中文字幕色伊伊| 99精品国产一区二区青青牛奶| 免费一级欧美片在线播放| 国内外成人免费激情在线视频| 欧美一级视频精品观看| 一区二区三区四区国产| 欧美日韩国产欧美日美国产精品| 亚洲国产精品成人| 蜜桃av一区二区在线观看| 久久国产精品亚洲va麻豆| 国产精品综合色区在线观看| 亚洲欧美三级伦理| 亚洲社区在线观看| 国产精品久久夜| 亚洲欧美在线免费观看| 99视频精品| 国产精品久久夜| 欧美一区二区视频在线观看2020| 久久精品综合一区| 亚洲免费网站| 国产亚洲欧美激情| 久久中文字幕导航| 久久久久久久久久码影片| 在线不卡a资源高清| 欧美激情久久久| 欧美理论在线播放| 亚洲一区尤物| 欧美夜福利tv在线| 亚洲国产精品成人精品| 91久久国产综合久久蜜月精品| 欧美精品99| 亚洲欧美不卡| 欧美一区二区三区免费视| 黑丝一区二区| 亚洲高清中文字幕| 欧美三级网址| 久久久www| 欧美高清在线观看| 校园春色综合网| 蜜臀久久久99精品久久久久久 | 亚洲二区在线| 亚洲精品中文字幕女同| 国产午夜亚洲精品不卡| 欧美成人福利视频| 欧美先锋影音| 免费在线亚洲欧美| 国产精品盗摄久久久| 久久综合中文| 欧美日本高清视频| 久久天堂精品| 欧美视频在线免费| 免费h精品视频在线播放| 欧美乱大交xxxxx| 久久久久久久久久久久久女国产乱 | 亚洲影院一区| **性色生活片久久毛片| 一本久久综合| 亚洲精品一区二区三区在线观看| 亚洲天堂av图片| 亚洲日本电影| 久久精品夜色噜噜亚洲aⅴ| 亚洲桃花岛网站| 蜜臀av国产精品久久久久| 欧美综合77777色婷婷| 欧美精品一区在线观看| 免费成人av在线| 国产日韩在线不卡| 正在播放亚洲| 正在播放日韩| 欧美精品成人在线| 欧美成人影音| 一区二区三区自拍| 亚洲欧美在线另类| 亚洲在线黄色| 欧美视频在线播放| 亚洲免费观看在线视频| 亚洲精品久久久久| 亚洲国产经典视频| 国产色综合久久| 亚洲午夜一区二区三区| 亚洲私拍自拍| 欧美日韩综合网| 日韩视频―中文字幕| 99视频精品免费观看| 欧美国产第二页| 亚洲国产第一页| 亚洲乱码国产乱码精品精天堂| 蜜桃av噜噜一区| 亚洲电影激情视频网站| 亚洲欧洲一区二区天堂久久| 男女精品网站| 亚洲国产欧美精品| 日韩午夜免费| 欧美日韩亚洲一区二区三区在线 | 欧美顶级大胆免费视频| 欧美大香线蕉线伊人久久国产精品| 狠狠久久五月精品中文字幕| 欧美亚洲在线播放| 久久美女性网| 亚洲国产成人av好男人在线观看| 久久一区亚洲| 亚洲欧洲精品一区二区| 夜夜嗨av一区二区三区网页 | 国产精品成人久久久久| 亚洲一区二区三区三| 久久精品国产成人| 激情六月婷婷久久| 欧美高清在线视频| 9色国产精品| 久久精品五月婷婷| 亚洲欧洲视频在线| 欧美性大战久久久久| 午夜在线视频一区二区区别| 裸体女人亚洲精品一区| 亚洲伦理在线| 国产精品亚洲美女av网站| 欧美综合二区| 亚洲人成在线播放| 欧美亚洲综合在线| 在线日韩av永久免费观看| 欧美精品一区二区三区一线天视频 | 麻豆久久婷婷| 在线天堂一区av电影| 国产一区二区av| 欧美日韩国产精品 | 亚洲婷婷在线| 麻豆久久精品| 亚洲欧美久久久| 一区二区视频在线观看| 欧美日韩卡一卡二| 久久精品国产一区二区电影| 日韩视频一区二区在线观看 | 久久久久久穴| 一本色道久久综合狠狠躁篇的优点| 国产精品免费久久久久久| 久久综合一区二区| 亚洲欧美激情诱惑| 亚洲清纯自拍| 欧美精品一区在线播放| 亚洲性色视频| 欧美成人在线免费观看| 午夜精品在线看| 日韩一级在线观看| 国产一区二区中文字幕免费看| 欧美好骚综合网| 久久精品国产免费| 亚洲网站在线看| 91久久午夜| 欧美大香线蕉线伊人久久国产精品| 午夜精品久久久久久久久久久久| 亚洲日本视频| 亚洲第一福利在线观看| 国产亚洲欧美日韩精品| 国产精品久久久久影院亚瑟 | 欧美一级专区| 宅男噜噜噜66一区二区66| 亚洲精品美女免费| 亚洲国产成人porn| 欧美大片免费看|