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

Fly me to the moon

the beauty of C++

位運(yùn)算之美——用+,-和位運(yùn)算實(shí)現(xiàn)正整數(shù)除法和取模(一)

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

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

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

    求給定整數(shù)的二進(jìn)制表示中1的個數(shù)
    考慮到n-1會把n的二進(jìn)制表示中最低位的1置0并把其后的所有0置1,同時不改變此位置前的所有位,那么n&(n-1)即可消除這個最低位的1。這樣便有了比順序枚舉所有位更快的算法:循環(huán)消除最低位的1,循環(huán)次數(shù)即所求1的個數(shù)。此算法的時間復(fù)雜度為O(n的二進(jìn)制表示中的1的個數(shù)),最壞情況下的復(fù)雜度O(n的二進(jìn)制表示的總位數(shù))。
 1//計算n的二進(jìn)制表示中1的個數(shù)
 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}
    既然有了求給定整數(shù)的二進(jìn)制表示中1的個數(shù)的辦法,那么想要求給定整數(shù)的二進(jìn)制表示中0的個數(shù)就很簡單了。事實(shí)上,在二進(jìn)制中,完全可以把0和1看作是對稱的兩個對象,取反操作(~)可以任意的切換這兩個對象,只要先對n進(jìn)行一次取反,然后再用上述算法即能得到二進(jìn)制表示中0的個數(shù)。首先看下面的代碼:
 1//計算n的二進(jìn)制表示中0的個數(shù)
 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}
    不知大家有沒有看出問題來?是的,~操作符會把所有高位的都取反,而不是只把有效位取反,所以我們需要一個能保持高位不變的位取反操作,下面是我的實(shí)現(xiàn),時間復(fù)雜度和求二進(jìn)制表示中1的個數(shù)的算法相同,都與二進(jìn)制表示中1的個數(shù)有關(guān):
 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}
    有了這個特殊的取反操作,求給定整數(shù)的二進(jìn)制表示中0的個數(shù)的辦法就簡單了:
 1//計算n的二進(jìn)制表示中0的個數(shù)
 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}
    看到這里,聰明的讀者肯定看出問題來了,其實(shí)我干了一件很蠢的事情??纯瓷鲜鏊惴ǖ臅r間復(fù)雜度,negate_bits花了O(n的二進(jìn)制表示中1的個數(shù)),while循環(huán)計算取反后的n的二進(jìn)制表示中1的個數(shù),事實(shí)上就是O(n的二進(jìn)制表示中0的個數(shù)),兩部分加起來其實(shí)就是二進(jìn)制表示總的有效位數(shù),換句話說,這個算法是線性的,而事實(shí)上,我們完全可以先線性地求出這個總的有效位數(shù),然后減去1的位數(shù),即得到0的位數(shù),根本不用費(fèi)那么大勁去整個保持高位的取反操作,兩者的時間復(fù)雜度在漸進(jìn)意義上也是相同的。所以,我犯傻了,但是這里又引出另一個問題:

    求給定整數(shù)的二進(jìn)制表示的有效位數(shù)
   
上面提到了線性地求這個位數(shù)(下文記為m),即“循環(huán)右移1位,記錄右移次數(shù)”,時間復(fù)雜度O(m)。但是我想,一看到這個題目,所有人的第一反應(yīng)應(yīng)該是floor(log2(n))+1吧,但是請注意,本文在一開始就規(guī)定了“不能使用庫例程”,那么在這個限制下該怎么做呢?有沒有比線性時間更好的算法呢?其實(shí)到目前為止我也沒有什么特別好的算法,希望誰有什么精妙的算法能指點(diǎn)一下,不要打我。。。
 1//求給定整數(shù)的二進(jìn)制表示的位數(shù),線性算法
 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}

    求大于等于給定整數(shù)的最小的2的整數(shù)次冪
    首先是最簡單的思路:求出n的二進(jìn)制表示的總位數(shù)m,于是1<<m即為所求值,當(dāng)然這里要排除n自身就是2的整數(shù)次冪的情況,復(fù)雜度O(m),實(shí)現(xiàn)如下:
 1//求大于等于n的最小的2的正整數(shù)冪,方法1
 2//時間復(fù)雜度O(n的二進(jì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}
    事實(shí)上這就涉及到上面求二進(jìn)制表示位數(shù)的問題,所以目前為止在此基礎(chǔ)上的算法都是線性時間的。   
    那有沒有不用計算位數(shù)m,從而效率更好的算法呢,能不能像在計算二進(jìn)制表示中1的個數(shù)時那樣根據(jù)1的個數(shù)來設(shè)計算法呢?回到那一題中,“n-1會把n的二進(jìn)制表示中最低位的1置0并把其后的所有0置1”,那么n|=n-1就把n的二進(jìn)制表示中最低位1后的所有0置1,再加上1,那么就把最低位1左移了一位。于是,便有了更好的算法:循環(huán)左移最低位的1,直到n是2的整數(shù)次冪。該算法跟二進(jìn)制表示中的1的個數(shù)和位置有關(guān),最壞時間復(fù)雜度還是O(二進(jìn)制表示位數(shù)),但是比起上一個實(shí)現(xiàn),這個算法在多數(shù)情況下都比上一個算法快。實(shí)現(xiàn)如下:
 1//求大于等于n的最小的2的正整數(shù)冪,方法2
 2//計算時間與n的二進(jìn)制表示中1的個數(shù)和位置有關(guān),比方法1效率高
 3//最壞情況下的時間復(fù)雜度與方法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}
    
    最后來一個簡單的擴(kuò)充題目:
    判斷給定的整數(shù)是不是4的整數(shù)次冪
    觀察4的整數(shù)次冪的特征,容易發(fā)現(xiàn)除了滿足n&(n-1)==0外,唯一的1位后的0的個數(shù)是偶數(shù),這從4x=22k也能簡單地得到。這就很直觀地衍生出一個簡單的算法:
 1//判斷n是否是4的整數(shù)次冪
 2bool is_4exp(unsigned int n)
 3{
 4    if(!is_2exp(n)) return false;
 5
 6    int bit_len = count_bit(n)-1;//線性時間求二進(jìn)制位數(shù)
 7    if((bit_len&0x1)!=1)
 8        return true;
 9    else
10        return false;
11}
    算法很直觀,但是比起is_2exp的常數(shù)時間is_4exp的線性時間總讓我覺得不能接受,不過無奈還是沒有想出好辦法來,哎。。。求大牛指點(diǎn)啊
   
    說明:寫這篇文章,已經(jīng)三次丟失全文了,把我快搞瘋了,firefox下好像有點(diǎn)問題,先把文章發(fā)上來,過會兒換到IE下繼續(xù)。。。
    再說明:換了IE后就沒再出問題了,不過寫著寫著發(fā)現(xiàn)寫了好久,先歇會兒,得看書補(bǔ)習(xí)功課了
    最后的說明:下次會給出本文最初提出的問題(只能用+,-和位運(yùn)算實(shí)現(xiàn)正整數(shù)除法(/)和取模(%))的實(shí)現(xiàn)。

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

評論

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

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

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

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

總結(jié)的不錯  回復(fù)  更多評論   

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

求給定整數(shù)的二進(jìn)制表示的有效位數(shù)

可以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;
}  回復(fù)  更多評論   

導(dǎo)航

<2010年11月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統(tǒng)計

常用鏈接

留言簿

隨筆分類

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久综合久久久久88| 亚洲欧美清纯在线制服| 一区二区精品在线| 亚洲二区视频| 1204国产成人精品视频| 欧美视频三区在线播放| 美女露胸一区二区三区| 久久精品视频播放| 欧美一区二区三区在线看| 欧美专区在线| 麻豆91精品91久久久的内涵| 欧美va天堂| 亚洲第一狼人社区| 久久婷婷影院| 亚洲欧洲在线播放| 亚洲欧美日韩国产精品| 久久精品免费电影| 欧美区国产区| 国产日韩欧美精品综合| 激情国产一区二区| 99亚洲伊人久久精品影院红桃| 亚洲五月六月| 美女精品视频一区| 99国产麻豆精品| 午夜精品视频在线观看一区二区| 亚洲欧美在线高清| 久久影音先锋| 艳女tv在线观看国产一区| 午夜免费日韩视频| 欧美aⅴ一区二区三区视频| 欧美色欧美亚洲高清在线视频| 国产一区二区三区最好精华液| 日韩一区二区精品葵司在线| 国产欧美不卡| 亚洲精品麻豆| 久久久噜噜噜久久| 99成人精品| 欧美.com| 怡红院精品视频| 亚洲欧美日韩国产中文在线| 你懂的视频一区二区| 午夜视频在线观看一区| 欧美日韩中文精品| 亚洲福利在线观看| 欧美与黑人午夜性猛交久久久| 亚洲国产成人精品久久久国产成人一区| 亚洲天堂视频在线观看| 亚洲精品在线三区| 久久国产免费| 国产精品免费一区二区三区在线观看| 亚洲第一网站免费视频| 久久久久se| 午夜亚洲伦理| 国产日韩亚洲欧美| 亚洲欧美乱综合| 一本一本久久a久久精品综合麻豆| 老牛影视一区二区三区| 国产综合网站| 久久久久久夜精品精品免费| 亚洲免费伊人电影在线观看av| 欧美午夜片在线观看| 99综合电影在线视频| 亚洲国产精品一区二区第四页av| 久久久精品2019中文字幕神马| 国产欧美日韩综合精品二区| 亚洲欧美日韩爽爽影院| 亚洲精品欧洲精品| 欧美日韩免费观看一区| 亚洲视频综合在线| 亚洲一级一区| 国内精品美女av在线播放| 久久久久国色av免费观看性色| 亚洲欧美精品在线| 国产专区综合网| 美女视频黄a大片欧美| 久久一区二区三区四区五区| 亚洲高清视频中文字幕| 欧美福利小视频| 欧美精品午夜视频| 亚洲综合精品一区二区| 在线视频你懂得一区二区三区| 国产精品日韩在线| 久久久亚洲成人| 免费观看欧美在线视频的网站| 欧美另类在线观看| 一区二区三区国产盗摄| 亚洲小视频在线观看| 国产日韩欧美精品一区| 免费观看一区| 欧美午夜电影完整版| 久久久成人网| 欧美激情综合五月色丁香| 亚洲伊人色欲综合网| 欧美在线精品一区| 亚洲精品韩国| 性欧美精品高清| 日韩视频在线免费观看| 亚洲欧美精品| 99re热精品| 欧美在线观看www| av成人福利| 久久成人精品电影| 亚洲深夜影院| 麻豆精品网站| 久久国内精品自在自线400部| 免费不卡亚洲欧美| 欧美在线观看一区二区| 欧美电影在线| 久久久综合激的五月天| 欧美成人午夜视频| 久久精品日产第一区二区| 欧美精品在线视频| 欧美成人午夜77777| 国产区欧美区日韩区| 亚洲精品免费在线观看| 国外成人在线视频网站| 亚洲欧美日韩国产综合在线| 久久久久久**毛片大全| 一本色道久久88亚洲综合88| 欧美一区二区三区在线视频 | 欧美精品久久99久久在免费线| 午夜亚洲伦理| 欧美性事在线| 9色国产精品| 在线午夜精品自拍| 欧美韩日高清| 欧美激情精品久久久久久蜜臀| 国产日韩欧美不卡| 亚洲自拍三区| 欧美一区二区三区精品| 欧美日韩三级视频| 亚洲精品一区二区三区福利| 亚洲第一成人在线| 久久精品人人做人人综合| 欧美在线一二三| 国产区精品在线观看| 欧美一二三视频| 久久大逼视频| 国内精品亚洲| 久久精品国产第一区二区三区最新章节 | 夜夜嗨av色综合久久久综合网| 久久综合一区二区| 欧美成人免费在线观看| 亚洲激情六月丁香| 亚洲精品欧洲精品| 一区二区三区高清不卡| 欧美三级精品| 亚洲午夜成aⅴ人片| 亚洲欧美日韩国产中文在线| 国产精品综合不卡av| 久久aⅴ乱码一区二区三区| 久久久噜噜噜久久久| 国产在线播精品第三| 久久久久久九九九九| 亚洲第一久久影院| 一区二区国产在线观看| 国产精品久久激情| 亚洲欧美日本日韩| 欧美在线免费视屏| 国产亚洲欧美aaaa| 欧美在线一级视频| 亚洲第一二三四五区| 亚洲性色视频| 国产婷婷色综合av蜜臀av| 久久久夜精品| 一本久久a久久精品亚洲| 亚洲女同在线| 亚洲成人资源网| 欧美日韩免费网站| 欧美专区在线| 亚洲精品欧美极品| 久久米奇亚洲| 99在线|亚洲一区二区| 欧美揉bbbbb揉bbbbb| 久久av一区二区三区漫画| 欧美国产日韩在线| 亚洲性线免费观看视频成熟| 国产亚洲一区二区精品| 老司机午夜精品视频| 一区二区激情| 亚洲高清自拍| 久久亚洲精品欧美| 亚洲制服丝袜在线| 亚洲国产成人av好男人在线观看| 欧美日韩一级大片网址| 久久久www成人免费无遮挡大片| 亚洲高清在线播放| 久久精品一区| 亚洲一区中文| 99国产精品视频免费观看| 国产日产欧产精品推荐色| 欧美国产日韩一区二区在线观看 | 久久久久久久久综合| 一区二区三区四区国产| 欧美激情精品久久久久| 久久国产精品亚洲77777| 亚洲一区二区免费看| 亚洲精品免费在线播放| 在线国产精品一区| 国产日韩欧美91|