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

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>
            香蕉精品999视频一区二区| 麻豆精品网站| 亚洲深夜福利| 欧美深夜福利| 亚洲欧美影音先锋| 欧美大片在线影院| 99亚洲伊人久久精品影院红桃| 免费观看日韩av| 亚洲视频碰碰| 你懂的国产精品| 性18欧美另类| 亚洲欧洲日产国产网站| 国产精品久久久久久久久借妻| 久久久久久婷| 亚洲欧美日韩国产综合在线| 欧美激情亚洲| 先锋影院在线亚洲| 亚洲精品美女免费| 精品91在线| 国产精品免费观看在线| 99成人精品| 午夜精品短视频| 亚洲欧洲三级| 国产日韩综合一区二区性色av| 国产麻豆日韩欧美久久| 日韩一区二区精品葵司在线| 狠狠v欧美v日韩v亚洲ⅴ| 欧美日韩高清在线播放| 欧美激情综合网| 欧美成人免费全部| 老司机免费视频一区二区| 亚洲在线日韩| 亚洲天堂av在线免费| 99视频精品免费观看| 欧美高清在线视频| 乱码第一页成人| 免费观看成人| 亚洲国产精品久久久久婷婷老年| 久久久久久免费| 久久成人综合视频| 中文一区字幕| 国产亚洲精品bv在线观看| 国产视频久久久久久久| 国产午夜精品久久久久久免费视 | 亚洲理伦电影| 欧美体内she精视频| 国产精品一区二区久久久久| 欧美午夜不卡| 国产精一区二区三区| 欧美日韩国产限制| 欧美日韩美女一区二区| 欧美精品一区在线| 欧美日韩亚洲一区二区三区在线 | 午夜欧美精品| 国产在线欧美日韩| 亚洲国产欧美一区| 久久蜜臀精品av| 免费在线播放第一区高清av| 欧美美女日韩| 国产精品亚洲不卡a| 国产精品视频大全| 好看不卡的中文字幕| 亚洲精品少妇网址| 小处雏高清一区二区三区| 欧美一区网站| 欧美mv日韩mv国产网站app| 亚洲品质自拍| 一本色道久久综合亚洲91| 亚洲女ⅴideoshd黑人| 久久久久久久综合色一本| 欧美极品在线观看| 欧美成人首页| 午夜亚洲性色福利视频| 久久久久亚洲综合| 快she精品国产999| 国产精品久久久久久久电影| 欧美激情一区二区| 国产农村妇女精品一区二区| 亚洲黄色视屏| 久久激情综合| 亚洲国产精品久久人人爱蜜臀| 亚洲欧美在线看| 这里只有精品丝袜| 开心色5月久久精品| 国产精品区二区三区日本| 欧美日一区二区三区在线观看国产免 | 99视频一区二区| 欧美护士18xxxxhd| 亚洲国产一区二区视频| 亚洲图片欧洲图片日韩av| 亚洲性感美女99在线| 日韩午夜电影| 欧美涩涩网站| 娇妻被交换粗又大又硬视频欧美| 亚洲乱码精品一二三四区日韩在线| 久久精品官网| 欧美大片免费观看| 激情另类综合| 日韩亚洲欧美综合| 欧美电影免费网站| 亚洲女同在线| 国产精品豆花视频| 亚洲视频久久| 欧美淫片网站| 国产自产女人91一区在线观看| 中文在线一区| 亚洲激情网址| 国产日韩在线看| 伊人久久综合97精品| 久久精品国语| 亚洲一区二区欧美日韩| 一区二区三区在线观看视频| 久久国产精品免费一区| 99re66热这里只有精品3直播 | 午夜在线精品偷拍| 欧美高潮视频| 免费成人毛片| 一区二区在线不卡| 亚洲一区在线观看免费观看电影高清| 在线免费高清一区二区三区| 午夜精品亚洲| 午夜精品久久久久久久男人的天堂 | 欧美黄色影院| 久久久xxx| 国产精品久久久久久福利一牛影视| 久久性色av| 国产精品揄拍500视频| 99热这里只有精品8| 日韩视频永久免费观看| 美女黄网久久| 欧美国产三级| 亚洲国产黄色| 国产精品综合| 午夜激情久久久| 欧美一区二区三区日韩视频| 欧美日韩黄色大片| 久久国产乱子精品免费女 | 日韩午夜在线播放| 欧美一区二区三区四区在线| 亚洲国产精品成人精品| 久久9热精品视频| 久久国产精品99精品国产| 国产精品一区二区在线观看| 亚洲欧美高清| 久久国产手机看片| 狠狠干狠狠久久| 欧美在线高清视频| 久久精品99国产精品| 国内综合精品午夜久久资源| 久久九九热免费视频| 欧美成人中文字幕在线| 亚洲精选中文字幕| 欧美久久电影| 亚洲欧美日韩另类| 久久字幕精品一区| 亚洲精品视频一区二区三区| 欧美日韩精品免费观看视频| 一区二区激情小说| 久久综合色8888| 亚洲国产福利在线| 欧美日韩免费高清| 一区二区三区精品久久久| 久久成人羞羞网站| 亚洲第一中文字幕在线观看| 欧美激情网友自拍| 亚洲图片欧洲图片日韩av| 久久er精品视频| 亚洲国产另类精品专区| 欧美日韩国产首页在线观看| 亚洲一区二区伦理| 欧美a级一区| 亚洲一级片在线看| 亚洲第一页中文字幕| 国产精品久久久久久久久果冻传媒 | 亚洲激情六月丁香| 亚洲欧美日韩精品综合在线观看| 国产视频观看一区| 欧美久久成人| 久久久国际精品| 一区二区三区欧美| 欧美成人黄色小视频| 亚洲永久字幕| 在线播放豆国产99亚洲| 国产精品入口夜色视频大尺度| 欧美成人r级一区二区三区| 亚洲欧美日韩精品久久| 麻豆9191精品国产| 一区二区三区免费看| 国产精品久久久久久户外露出 | 亚洲福利视频一区二区| 国产精品揄拍500视频| 欧美日韩国产欧美日美国产精品| 中国女人久久久| 欧美电影免费观看高清| 久久久久久亚洲精品不卡4k岛国| 亚洲精品乱码久久久久久日本蜜臀| 国产伦理一区| 久久全国免费视频| 国产精品视频网址| 一区二区三区欧美|