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

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;
}  回復  更多評論   

導航

<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統計

常用鏈接

留言簿

隨筆分類

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            麻豆精品在线播放| 欧美日韩一区视频| 亚洲乱码国产乱码精品精天堂| 欧美一区免费| 久久米奇亚洲| 你懂的国产精品| 亚洲人成网站777色婷婷| 夜夜嗨av一区二区三区网站四季av| 久久在线播放| 日韩系列欧美系列| 亚洲激情电影中文字幕| 国产日韩欧美一区在线| 欧美a级片一区| 免费成人你懂的| 久久久久久久999| 亚洲欧美美女| 香蕉久久精品日日躁夜夜躁| 9久re热视频在线精品| 欧美不卡视频| 亚洲国产精品毛片| 欧美在线看片a免费观看| 亚洲综合精品| 久久五月天婷婷| 亚洲福利电影| 亚洲在线观看免费视频| 亚洲国产高清一区| 久久频这里精品99香蕉| 亚洲欧美激情精品一区二区| 一个色综合av| 午夜欧美精品久久久久久久| 欧美中文在线视频| 欧美另类视频| 美女999久久久精品视频| 久久久久女教师免费一区| 欧美成人精品影院| 国产日韩综合| 一本一道久久综合狠狠老精东影业| 午夜久久福利| 日韩亚洲精品视频| 久久米奇亚洲| 国产午夜一区二区三区| 亚洲欧美日韩直播| 亚洲伦伦在线| 欧美激情精品久久久久久久变态| 国产啪精品视频| 亚洲天堂av在线免费| 午夜亚洲性色福利视频| 欧美电影在线| 欧美在线免费播放| 国产九九视频一区二区三区| 亚洲看片网站| 亚洲高清视频在线| 欧美在线视频免费观看| 国产欧美精品一区二区色综合 | 欧美日本精品| 亚洲黄色av一区| 欧美大尺度在线| 久久伊伊香蕉| 亚洲夫妻自拍| 欧美国产视频在线| 牛人盗摄一区二区三区视频| 韩日在线一区| 你懂的国产精品| 欧美成人按摩| 99精品国产在热久久| 亚洲人体1000| 国产精品久久一级| 欧美一区亚洲| 久久先锋影音| 亚洲精品国产无天堂网2021| 亚洲高清不卡在线| 欧美日本精品| 欧美一区二区视频网站| 久久gogo国模裸体人体| 1024精品一区二区三区| 亚洲国产婷婷香蕉久久久久久99 | 亚洲午夜一二三区视频| aa级大片欧美| 国产精品欧美经典| 久久久最新网址| 欧美1区2区视频| 亚洲女同同性videoxma| 欧美在线视频二区| 日韩视频免费在线| 欧美一区二区三区久久精品| 在线 亚洲欧美在线综合一区| 欧美激情精品久久久久久久变态 | 亚洲美女精品成人在线视频| 国产精品九九| 欧美1区视频| 欧美日韩精品免费观看视一区二区| 亚洲欧美精品中文字幕在线| 久久久久久久久综合| 亚洲视频电影图片偷拍一区| 午夜精品久久久久久久99热浪潮| 精品99一区二区| 亚洲美女在线观看| 国产综合久久久久久| 亚洲精品欧美激情| 国产日本欧美一区二区三区| 亚洲国产精品久久久久久女王| 国内在线观看一区二区三区| 在线视频日韩精品| 国产日韩欧美自拍| 亚洲国产日韩一区二区| 国产精品一区二区三区久久久| 久久综合久久综合久久| 欧美丝袜一区二区三区| 欧美成人蜜桃| 国产精品一区二区久久久| 欧美激情一区二区三区全黄 | 久久成人国产精品| 午夜精品区一区二区三| 男女av一区三区二区色多| 久久精品中文字幕免费mv| 国产精品sm| 日韩一级大片在线| 亚洲青涩在线| 久久久噜噜噜久久中文字幕色伊伊| 亚洲资源av| 欧美另类在线观看| 亚洲国产精品一区在线观看不卡| 国内精品99| 性欧美8khd高清极品| 亚洲伊人伊色伊影伊综合网| 欧美岛国在线观看| 欧美成人在线影院| 激情小说另类小说亚洲欧美 | 欧美调教视频| 亚洲美女在线观看| 一本到高清视频免费精品| 欧美美女bb生活片| 亚洲免费观看| 亚洲一区精品在线| 国产精品久久久一区二区| 在线午夜精品自拍| 亚洲影院免费观看| 国产精品捆绑调教| 亚洲少妇在线| 亚洲欧美国产精品桃花| 国产精品国产一区二区| 亚洲视频精选| 欧美伊人影院| 国语自产精品视频在线看8查询8 | 一本色道久久综合狠狠躁篇怎么玩| 日韩亚洲国产欧美| 欧美日韩一二三四五区| 一区二区三区 在线观看视频| 亚洲午夜伦理| 国产视频观看一区| 久久日韩粉嫩一区二区三区| 欧美大片免费观看在线观看网站推荐| 一区在线观看| 欧美久久一区| 亚洲淫片在线视频| 老司机aⅴ在线精品导航| 亚洲国产女人aaa毛片在线| 欧美另类视频在线| 午夜精品久久久久久 | 亚洲一区国产| 另类尿喷潮videofree| 日韩亚洲精品在线| 国产日韩精品一区二区浪潮av| 亚洲午夜久久久| 免费视频一区二区三区在线观看| 久久精品五月| 亚洲国产第一页| 日韩一区二区福利| 国产欧美日韩免费| 欧美成人一区二免费视频软件| 亚洲精选中文字幕| 久久久视频精品| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 欧美国产日韩在线| 亚洲欧美不卡| 最新国产の精品合集bt伙计| 国产精品久久一区二区三区| 久久精品在线| 一区二区三区毛片| 欧美成人亚洲成人| 欧美一区二区播放| 亚洲免费成人av| 狠狠久久五月精品中文字幕| 欧美精品久久99久久在免费线| 亚洲欧美日韩综合| 99www免费人成精品| 久久综合伊人77777麻豆| 亚洲影音先锋| 99精品视频免费全部在线| 国内精品视频在线观看| 欧美午夜精品久久久久久浪潮| 久久久久久久久久久久久久一区 | 亚洲午夜av| 日韩视频三区| 亚洲国产裸拍裸体视频在线观看乱了| 欧美亚洲网站| 亚洲自拍偷拍麻豆| 亚洲最新视频在线| 亚洲精品女人| 亚洲国产日韩在线|