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

C++之竹

無論是太陽下,還是風(fēng)雨中,都要成長!

常用鏈接

統(tǒng)計(jì)

最新評(píng)論

不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算

最近,在看《劍指Offer——名企面試官精講典型編程題》一書,當(dāng)看到“面試題47:不用加減乘除做加法”時(shí),經(jīng)過一分鐘左右思考后,得出了思路,跟書上一對(duì)照,基本一致,呵呵O(∩_∩)O~。于是,隨即又開始思考:加法是實(shí)現(xiàn)了,那么減法、乘法還有除法又該怎么實(shí)現(xiàn)呢?一番思考與分析后,得出算法,寫出代碼,測(cè)試通過,Happy!!\(^o^)/~

 接下來,就將我的算法與代碼展示如下,還請(qǐng)有更好算法的牛人不吝賜教!!

 

【1. 加法】

 因本人的算法與《劍指Offer——名企面試官精講典型編程題》中一致,就不做贅述,而只貼出代碼。

代碼1.1 加法:計(jì)算a+b

int Add(int a, int b)
{
    
int sum = a ^ b;
    
int carry = a & b;
    
while (carry != 0{
        a 
= sum;
        b 
= carry << 1;
        sum 
= a ^ b;
        carry 
= a & b;
    }


    
return sum;
}

【2. 減法】

方案一:通過Add函數(shù)的實(shí)現(xiàn)

按常規(guī)思路,根據(jù)加減運(yùn)算的互反性(即,減去一個(gè)數(shù)等于加上這個(gè)數(shù)的相反數(shù)),然后利用前面已實(shí)現(xiàn)的Add函數(shù)來進(jìn)行實(shí)現(xiàn)。

按這個(gè)思路,我們首先要做到對(duì)一個(gè)整數(shù)取相反數(shù),不能使用運(yùn)算符“-”,那么就只能根據(jù)C++上兩個(gè)互為相反數(shù)的int型數(shù)據(jù)的二進(jìn)制結(jié)構(gòu)關(guān)系——整數(shù)的相反數(shù)等于該數(shù)按位取反再加1,來設(shè)計(jì)如下的函數(shù)了。

代碼2.1 取整數(shù)n的相反數(shù)

int OppositeNumber(int n)
{
    
return Add(~n, 1);
}

然后就可以通過Add函數(shù)來實(shí)現(xiàn)減法了。

代碼2.2 減法一:計(jì)算a-b

int Subtract(int a, int b)
{
    
return Add(a, OppositeNumber(b));
}

畢竟是作為對(duì)思維開放的一個(gè)鍛煉,所以對(duì)于直接的減法算法的思考還是值得的。于是就有了下面的方案二。

方案二:直接通過位操作實(shí)現(xiàn)減法

算法是得通過二進(jìn)制位計(jì)算來實(shí)現(xiàn)的,所以在分析減法時(shí)從二進(jìn)制減法計(jì)算的角度去考慮將更合適。那么,兩個(gè)二進(jìn)制形式整數(shù)的減法操作又是怎樣進(jìn)行的呢?

  1. 首先,如果減數(shù)為0,則被減數(shù)即為減法的結(jié)果,運(yùn)算結(jié)束。
    但如果減數(shù)不為0,我們可以先把被減數(shù)和減數(shù)上同為1的位從兩個(gè)數(shù)上去除。至于如何分離出值同為1的位,則可以通過求位與操作來做到;而把這些1分別中被減數(shù)和減數(shù)中去除,則可以通過按位異或來的操作來實(shí)現(xiàn)。
  2. 經(jīng)步驟1處理后,被減數(shù)和減數(shù)在對(duì)應(yīng)的位上,將或者通為0,或者分別為0和1,卻不會(huì)同為1。此時(shí):
    如果對(duì)應(yīng)位被減數(shù)=1,而減數(shù)=0,則所得結(jié)果對(duì)應(yīng)位也為1;
    如果對(duì)應(yīng)位被減數(shù)=0,而減數(shù)=1,則所得結(jié)果對(duì)應(yīng)位還是1,但此時(shí)須向前一位借1;
    即,通過被減數(shù)與減數(shù)作位異或的操作得到臨時(shí)結(jié)果,和通過對(duì)減數(shù)左移一位得到需從臨時(shí)結(jié)果中減去的借數(shù)。
  3. 于是,經(jīng)過步驟2后,原來的減法變成了要求:臨時(shí)結(jié)果 - 借數(shù)
    很明顯,只要以臨時(shí)結(jié)果為被減數(shù),借數(shù)為減數(shù),重復(fù)步驟1~3即可。

上述步驟中,如果被減數(shù)或減數(shù)為負(fù)數(shù),由負(fù)數(shù)的二進(jìn)制位結(jié)構(gòu),可以保證上述步驟的處理仍適用,證明過程就請(qǐng)恕我在這里略去了。具體的實(shí)現(xiàn)代碼如下。

代碼2.3 減法二:計(jì)算a-b

int Subtract(int a, int b)
{
    
while (b != 0
    
{
        
int sameBits = a & b;
        a 
^= sameBits;
        b 
^= sameBits;
        a 
|= b;
        b 
<<= 1;
    }


    
return a;
}

※注:上述加法和減法中,按代碼安全性,其實(shí)還應(yīng)考慮計(jì)算后數(shù)據(jù)溢出的情況,這里我偷了下懶,省去了。不過下面的乘除法,我會(huì)提供包含了異常處理的代碼。異常處理的方式,我采用了throw拋出的方式。

 【3. 乘法】

為了方便對(duì)數(shù)據(jù)溢出的統(tǒng)一處理,在進(jìn)行計(jì)算前,我先保存了被乘數(shù)與乘數(shù)的符號(hào)信息,并當(dāng)被乘數(shù)或乘數(shù)為負(fù)時(shí),利用上面的OppositeNumber函數(shù),統(tǒng)一的轉(zhuǎn)換為正整數(shù)(或0),然后再來進(jìn)行乘法的運(yùn)算。為了能同時(shí)適應(yīng)32位和64位的整形數(shù),在取符號(hào)信息與設(shè)置溢出判斷位時(shí),使用了以下的輔助宏和函數(shù)。

代碼3.1 輔助宏與輔助函數(shù)

#define BITS_OF_ONE_BYTE     8
#define SIGN_BIT_FLAG_FOR_BYTE   0x80     // for signed byte/char

int SignBitFlagOfInt()
{
    
static int signBitFlag = 0;

    
static bool bIs1stCalled = true;
    
if (bIs1stCalled)
    
{
        
int temp = SIGN_BIT_FLAG_FOR_BYTE;
        
while (temp != 0
        
{
            signBitFlag 
= temp;
            temp 
<<= BITS_OF_ONE_BYTE;
        }

        bIs1stCalled 
= false;
    }


    
return signBitFlag;
}

乘法的算法。考慮到:

  1. 整數(shù)n乘以2k == n << k
  2. C++中的任何一個(gè)非負(fù)int型數(shù)據(jù)都可以表示為如下的形式:
    k0×20+k1×21+...+km×2m
    的形式。(其中:ki∈{0, 1}, i∈{0, 1, ... , m}, 32位int型m = 30, 64位int型m = 62)

于是,就可以利用乘法分配率,通過循環(huán)累加,進(jìn)行乘法的運(yùn)算了。參考代碼3.2。

代碼3.2 乘法:計(jì)算a×b

int Multiply(int a, int b)
{
    
int signStatA = a & SignBitFlagOfInt();
    
if (signStatA != 0)
    
{
        a 
= OppositeNumber(a);
    }


    
int signStatB = b & SignBitFlagOfInt();
    
if (signStatB != 0)
    
{
        b 
= OppositeNumber(b);
    }


    
int overFlowFlag = SignBitFlagOfInt(); // used for checking if the signed int data overflowed.
    int product = 0// the result of |a| * |b|
    for (int curBitPos = 1; curBitPos != 0; curBitPos <<= 1)
    
{
        
if ((b & curBitPos) != 0)
        
{
            product 
= Add(product, a);
            
if (((a & overFlowFlag) != 0
                
|| ((product & overFlowFlag) != 0))
            
{
                
throw std::exception("The result data war overflowed.");
            }

        }

        a 
<<= 1;
    }


    
return ((signStatA ^ signStatB) == 0? product : OppositeNumber(product);
}

【4. 除法】

整數(shù)的除法,不同于乘法,除法所得的商的絕對(duì)值必然不大于被除數(shù)的絕對(duì)值,而所得余數(shù)的絕對(duì)值則必然小于除數(shù)的絕對(duì)值。所以,在設(shè)計(jì)除法函數(shù)的時(shí)候,無需考慮數(shù)據(jù)溢出的問題。但對(duì)于除法,卻也有它自己的禁忌——除數(shù)不能為“0”。

為了處理的方便,準(zhǔn)備工作同乘法一樣,記錄下被除數(shù)與除數(shù)的符號(hào)狀態(tài)(比便在計(jì)算出結(jié)果后進(jìn)行符號(hào)的調(diào)整),并當(dāng)被除數(shù)或除數(shù)為負(fù)時(shí),通過函數(shù)OppositeNumber將其轉(zhuǎn)換為相反數(shù)。于是,接下來,我就只需考慮“非負(fù)整數(shù)(>=0)÷正整數(shù)(>0)”的情況了。對(duì)這種情況,計(jì)算過程如下:

  1. 預(yù)備工作:置商為0;
  2. 判斷“被除數(shù)>=除數(shù) ”是否成立:
    成立,繼續(xù)步驟3;
    不成立,被除數(shù)的值賦給余數(shù),計(jì)算結(jié)束。
  3. 備份除數(shù),并設(shè)置商分子(一個(gè)臨時(shí)變量,最終需加到商上面,故暫且如此命名)為1;
    對(duì)商分子和除數(shù)同步向左移位,直到繼續(xù)移位將大于被除數(shù)時(shí)為止;
  4. 從被除數(shù)上減去除數(shù),并將商加上商分子。
  5. 通過備份的除數(shù)值還原除數(shù),跳轉(zhuǎn)到步驟2繼續(xù)執(zhí)行。

對(duì)應(yīng)的代碼參加代碼4.1。

代碼4.1 除法:計(jì)算a÷b 

int Divide(int a, int b, int * pRem /*= NULL*/)
{
    
if (b == 0)
    
{
        
throw std::exception("Invalid divisor!! (The divisor can't be 0!)");
    }


    
int signStatA = a & SignBitFlagOfInt();
    
if (signStatA != 0)
    
{
        a 
= OppositeNumber(a);
    }


    
int signStatB = b & SignBitFlagOfInt();
    
if (signStatB != 0)
    
{
        b 
= OppositeNumber(b);
    }


    
int quotient = 0;
    
int backupB = b;
    
while (a >= b) 
    
{
        
int tempB = b << 1;
        
int tempQ = 1;
        
while ((tempB <= a) && ((tempB & SignBitFlagOfInt()) == 0))
        
{
            b 
= tempB;
            tempQ 
<<= 1;
            tempB 
<<= 1;
        }


        a 
= Subtract(a, b);
        quotient 
|= tempQ;
        b 
= backupB;
    }


    
if (pRem != NULL)
    
{
        
*pRem = a;
    }


    
if ((signStatA != 0&& (a != 0))
    
{
        quotient 
= Add(quotient, 1);
        
if (pRem != NULL)
        
{
            
*pRem = Subtract(b, *pRem);
        }

    }


    
return ((signStatA ^ signStatB) == 0? quotient : OppositeNumber(quotient);
}

※注:函數(shù)的返回值即為所求的商;
       參數(shù)pRem為余數(shù)的傳出參數(shù),其默認(rèn)值NULL,表示當(dāng)前無需關(guān)注余數(shù)。

 

posted on 2012-03-30 01:30 青碧竹 閱讀(5009) 評(píng)論(7)  編輯 收藏 引用 所屬分類: 算法相關(guān)

評(píng)論

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-30 13:02 遠(yuǎn)行

搜了下那本書,發(fā)現(xiàn)好像沒出版,lz有那本書的文檔能不能發(fā)一份啊,
愛好書之情難自抑啊。。。  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-30 14:40 FiO

@遠(yuǎn)行
http://book.douban.com/subject/6966465/  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-30 18:26 遠(yuǎn)行

沒錢買書,只看電子版。。。@FiO
  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-30 19:24 flyinghearts


嚴(yán)格的講,這些方法只能用于無符號(hào)數(shù)。對(duì)有符號(hào)數(shù)這樣的做法是不通用的。 google 一補(bǔ)數(shù)。

  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-30 19:49 青碧竹

@flyinghearts
在目前計(jì)算機(jī)內(nèi)負(fù)整數(shù)通過對(duì)其絕對(duì)值進(jìn)行求反+1來存儲(chǔ)的前提下,這些算法完全適用于有符號(hào)整數(shù)。  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-03-31 13:15 SwordLance

這類問題,只要知道CPU的運(yùn)算器是怎么做的,用程序模擬即可。  回復(fù)  更多評(píng)論   

# re: 不使用 +-×÷ 運(yùn)算符來實(shí)現(xiàn) 加減乘除 四項(xiàng)運(yùn)算 2012-04-01 00:13 青碧竹

@SwordLance
是的。  回復(fù)  更多評(pí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>
            欧美电影在线播放| 日韩手机在线导航| 日韩视频三区| 亚洲精品日产精品乱码不卡| 亚洲精品社区| 夜夜嗨av一区二区三区网站四季av | 亚洲精品久久久久久下一站 | 国产欧美日韩一区二区三区在线| 欧美日韩亚洲一区二区三区| 欧美性做爰毛片| 国产字幕视频一区二区| 亚洲国产成人精品视频| 亚洲精品一区中文| 午夜视频在线观看一区二区三区| 久久久久久久波多野高潮日日| 欧美成人一品| 亚洲一区区二区| 久久亚洲免费| 国产精品久久久久久久久久尿| 韩国福利一区| 亚洲一区高清| 国产日韩欧美在线播放不卡| 在线播放中文一区| 亚洲天堂偷拍| 女同性一区二区三区人了人一| 亚洲精选一区| 久久视频一区| 国产欧美日韩在线视频| 亚洲乱码精品一二三四区日韩在线| 午夜精品美女自拍福到在线| 欧美黄色视屏| 欧美一区二区三区四区在线观看地址| 久久亚洲精品一区| 国产毛片一区二区| 一区二区电影免费观看| 美女网站在线免费欧美精品| 亚洲一区二区三区中文字幕在线 | 美日韩丰满少妇在线观看| 日韩网站免费观看| 久久中文在线| 国产一区日韩一区| 亚洲欧美激情一区| 亚洲精品久久7777| 久久亚洲国产成人| 国产亚洲精品高潮| 一区二区精品在线| 亚洲黄色成人网| 久久免费一区| 国内精品久久久久久久97牛牛| 亚洲综合社区| 日韩亚洲综合在线| 欧美日韩国产成人在线91| 亚洲国产成人精品久久| 久久天堂精品| 久久精品99无色码中文字幕| 国产婷婷精品| 欧美在线观看网站| 亚洲视频在线视频| 国产精品成av人在线视午夜片| 中文国产成人精品| 亚洲理伦电影| 国产精品久久久一区二区三区| 亚洲午夜精品一区二区| 在线午夜精品自拍| 国产精品久久久久久久久久妞妞| 亚洲永久精品大片| 亚洲一区二区综合| 国产三区二区一区久久| 久久久久国产精品午夜一区| 久久综合精品国产一区二区三区| 亚洲国产精品久久91精品| 欧美二区在线观看| 欧美精品一区视频| 欧美亚洲三区| 久久免费视频网站| 一区二区三区色| 亚洲综合二区| 亚洲成人在线| 亚洲久久一区| 日韩天堂av| 日韩一级在线观看| 欧美大片va欧美在线播放| 久久综合久色欧美综合狠狠| 亚洲乱码国产乱码精品精可以看| 亚洲人永久免费| 国产精品一区二区久久精品| 久久综合中文字幕| 欧美日韩aaaaa| 久久久国产成人精品| 免费日韩av| 亚洲欧美日韩国产一区二区| 久久精品国产v日韩v亚洲| 日韩网站免费观看| 午夜精品在线视频| 亚洲乱码视频| 久久精品一区二区三区不卡| 99热免费精品在线观看| 亚洲男人的天堂在线| 亚洲精品国偷自产在线99热| 在线一区二区日韩| 91久久久久久| 欧美综合激情网| 亚洲在线观看视频网站| 久久婷婷亚洲| 久久精品国内一区二区三区| 欧美精品999| 久久婷婷成人综合色| 欧美日韩精品不卡| 欧美成人免费播放| 国产亚洲精品资源在线26u| 亚洲免费大片| 亚洲激情在线播放| 欧美一区二区三区成人| 亚洲欧美综合v| 欧美日韩一区二区三区在线观看免 | 国产日韩综合一区二区性色av| 亚洲七七久久综合桃花剧情介绍| 国产日韩在线一区| 亚洲一区二区欧美日韩| 亚洲日本电影| 久久久亚洲人| 久久一二三区| 国产一区在线视频| 亚洲欧美日韩中文视频| 亚洲一区免费在线观看| 欧美精品在线看| 亚洲国产精品成人久久综合一区| 依依成人综合视频| 欧美一区二区三区视频在线观看| 亚洲一区在线观看免费观看电影高清| 久久综合影视| 亚洲国产高清高潮精品美女| 亚洲国产精品一区二区久| 久久九九99| 免费在线观看成人av| 亚洲高清在线| 久久综合九九| 亚洲国产精品专区久久| 夜夜嗨av一区二区三区网页| 欧美日韩中文字幕在线| 亚洲一区二区伦理| 欧美日韩国产91| 日韩亚洲欧美高清| 亚洲女与黑人做爰| 国产欧美日韩视频一区二区三区| 亚洲欧美日韩国产中文在线| 午夜精品理论片| 狠狠色狠狠色综合人人| 麻豆freexxxx性91精品| 91久久精品一区二区三区| 日韩视频在线一区二区三区| 欧美日韩国产综合视频在线观看中文| 一本色道久久综合| 欧美资源在线| 91久久久久| 国产精品久久久久天堂| 香蕉av777xxx色综合一区| 蜜桃av一区| 亚洲天堂成人在线观看| 国产婷婷色一区二区三区在线 | 国产一区二区三区在线播放免费观看 | 欧美一区二区三区日韩视频| 国产美女诱惑一区二区| 久久青青草原一区二区| 亚洲成人在线视频播放 | 午夜精品国产更新| 久久尤物电影视频在线观看| 亚洲国产天堂久久综合| 欧美日韩在线三区| 欧美在线999| 亚洲国产美女| 欧美一区激情| 亚洲国产欧美另类丝袜| 国产精品久久久久久久久久免费| 欧美中文字幕在线播放| 亚洲精品乱码久久久久久蜜桃麻豆| 西瓜成人精品人成网站| 亚洲黄色一区二区三区| 国产精品亚洲综合一区在线观看 | 亚洲精品国产精品国产自| 欧美一区深夜视频| 日韩亚洲不卡在线| 黄色日韩在线| 国产精品久久网站| 欧美精品麻豆| 久久三级福利| 午夜一区不卡| 一本色道久久综合| 亚洲国产91| 狂野欧美激情性xxxx欧美| 亚洲欧美色婷婷| 一区二区不卡在线视频 午夜欧美不卡在 | 美女亚洲精品| 香蕉久久一区二区不卡无毒影院| 亚洲国产婷婷| 欧美国产91| 老司机aⅴ在线精品导航| 亚洲男人的天堂在线aⅴ视频| 亚洲黄一区二区| 伊人久久噜噜噜躁狠狠躁 |