• <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>

            elva

            大數(shù)四則運(yùn)算的C++實(shí)現(xiàn)

            大數(shù)四則運(yùn)算的C++實(shí)現(xiàn)



            [摘要] 大數(shù)運(yùn)算不僅僅運(yùn)用在密碼學(xué)中,還運(yùn)用在一些物理學(xué)研究、生物學(xué),化學(xué)等科目中。大數(shù)運(yùn)算,意味著參加的值和計(jì)算結(jié)果通常是以上百位數(shù),上千位數(shù)以及更大長(zhǎng)度之間的整數(shù)運(yùn)算。例如大家所熟知圓周率π的值,在一般的數(shù)值計(jì)算中用到圓周率的不須要多大的精度,但在計(jì)算一些星球或是星系上的體積面積時(shí)便顯的誤差很大了,這就要求π值計(jì)算的精度達(dá)到幾百萬(wàn)位甚至更高,才能縮小誤差。人工計(jì)算是遠(yuǎn)遠(yuǎn)不行了,而且本身誤差也無(wú)法估計(jì)。只有在計(jì)算機(jī)中用大數(shù)運(yùn)算求π值了。又如,考古學(xué)家計(jì)算石頭內(nèi)的碳元素衰變來(lái)考證地球形成的時(shí)間,更是將計(jì)算的結(jié)果精確到了百年以內(nèi)。所以說(shuō)大數(shù)的運(yùn)算是涉及領(lǐng)域多,應(yīng)用范廣,與我們生活息息關(guān)。在此,我采用一個(gè)在C語(yǔ)言下實(shí)現(xiàn)計(jì)算大數(shù)運(yùn)算的一個(gè)程序?yàn)槔v解包括了大數(shù)的加法,減法,乘法和除法及求冪運(yùn)算的算法及代碼。

            [關(guān)鍵詞] 大數(shù)計(jì)算 網(wǎng)絡(luò)安全 密碼學(xué)







                隨著計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)的發(fā)展和因特網(wǎng)的廣泛普及,網(wǎng)絡(luò)安全事故逐年增加,黑客的攻擊已經(jīng)和病毒并列成為對(duì)信息安全影響最嚴(yán)重的兩大危害。其很大程度上是被黑客破解了用戶的計(jì)算機(jī)名及登陸密碼及資料的加密較差,而使得黑客來(lái)對(duì)網(wǎng)民的資料如同自己般的隨意更改和破壞。而安全的密碼和賬號(hào)成為了網(wǎng)民的安全之本,怎么才能提高安全問(wèn)題成為的人們和社會(huì)關(guān)注的問(wèn)題。而加密大部又是以大素?cái)?shù)的計(jì)算為基礎(chǔ)的,如非對(duì)稱密碼體制RSA的安全性依賴于對(duì)大數(shù)進(jìn)行因數(shù)分解的耗時(shí)性。一個(gè)二進(jìn)制數(shù)n的因數(shù)分解所需的機(jī)器周期大約是exp{[ln(n)ln(ln(n))]1/2}。若機(jī)器周期為1μs,b為二進(jìn)制數(shù)的位數(shù),分解 n=2b 所需時(shí)間如下表所示:

            位數(shù) 100 200 300 500 750 1000
            時(shí)間 30秒 3天 9年 1兆年 2*109年 6*1015年

                實(shí)際應(yīng)用中,p、q的選擇都在10200 數(shù)字以上,這樣每個(gè)明文塊的二進(jìn)制位數(shù)可達(dá)664比特,即83個(gè)字節(jié)。而DES只有8個(gè)字符。一般認(rèn)為,對(duì)于當(dāng)前的計(jì)算機(jī)水平,選擇1024位長(zhǎng)的密鑰就可認(rèn)為是無(wú)法攻破的了。


            1. 數(shù)字存儲(chǔ)的實(shí)現(xiàn)
                大數(shù)計(jì)算的因數(shù)和結(jié)果精度一般是少則數(shù)十位,多則幾萬(wàn)位。在C語(yǔ)言中定義的類型中精度最多只有二十多位,因而我們采取用鏈表存貯的方式來(lái)存放大數(shù)。在計(jì)算中會(huì)用到從高位開始計(jì)算,和從低位開始計(jì)算數(shù)值的兩種情況。所以我們將鏈表定義為雙向鏈表,其中為一個(gè)單元來(lái)存貯數(shù)據(jù),一個(gè)指針指向前方的數(shù)據(jù),另一個(gè)指向后的數(shù)據(jù)。其結(jié)構(gòu)為:

            struct Node    // 定義一個(gè)雙向鏈表用來(lái)存貯結(jié)果
            {
            char data;     // 數(shù)據(jù)*定義為字符的原因:要顯示負(fù)號(hào)
            Node *next;    // 尾指針
            Node *ahead;   // 首指針
            };

             

            2. 各種算法
            2.1 加法運(yùn)算的實(shí)現(xiàn)
                加法計(jì)算還是比較容易的,我們也是先從低位算起,因?yàn)橹豁氁獙?duì)應(yīng)的位相加,再加上前一位的進(jìn)位,再去判斷是否本位是否有進(jìn)位, 有則把本位數(shù)字改為減去它的權(quán),也就是10,再置進(jìn)位為1。如果沒有進(jìn)位,則給進(jìn)位賦值0。

                在程序時(shí)應(yīng)注意:
                1、兩個(gè)加數(shù)中那一個(gè)數(shù)的位數(shù)長(zhǎng),以位數(shù)長(zhǎng)的作為循環(huán)變量;
                2、結(jié)束循環(huán)時(shí),不僅僅是最后一位加完就停止,還應(yīng)加入如果有進(jìn)位,也要再循環(huán)一次。如最后一位是9,進(jìn)位是1,則相加時(shí)進(jìn)位,要加上進(jìn)位這一位值。具體看代碼,輸入輸出時(shí)和乘法的一樣。
            /*--------------------------------------------------------------------------
            *函數(shù)名稱: 大數(shù)加法
            *函數(shù)過(guò)程:1 比較兩個(gè)數(shù)那一個(gè)長(zhǎng)
            * 2 以長(zhǎng)的作為循環(huán)次數(shù)
            * 3 對(duì)應(yīng)項(xiàng)相加 進(jìn)位存貯直到下高位相加用
            * 4 直到循環(huán)結(jié)束
            * 5 !!!!!!沒設(shè)計(jì)負(fù)數(shù)相加
            *入口參數(shù):numa,numb,result字符串
            *出口參數(shù):無(wú)
            *編輯環(huán)境:winSP2 + VC2003 + C++
            *--------------------------------------------------------------------------*/

            void addition(char *numa, char *numb,char *result) // 計(jì)算兩大數(shù)之和
            {
              char *pna = findend(numa); // 指向numa的一個(gè)指針。point numa pna 指向乘數(shù)的最低位,
              char *pnb = findend(numb); //指向numb的一個(gè)指針 //pnb 指向被乘數(shù)的最低位,
              int along=(int)strlen(numa); //標(biāo)記數(shù)字a的長(zhǎng)度;
              int blong=(int)strlen(numb); //標(biāo)記數(shù)字b的長(zhǎng)度;
              int times = 0; // 標(biāo)致要計(jì)算多少次。
              int carry=0,temp_result; //存貯進(jìn)位 和臨時(shí)結(jié)果的
              Node *head, // 用于存貯頭指針
                *pstart, // 用于存貯計(jì)算時(shí)的首指針
                *pnew; //作于申請(qǐng)新結(jié)點(diǎn)
              head = pstart =new Node; //初始化首結(jié)點(diǎn)和頭結(jié)點(diǎn)。
              pstart -> data = 0;
              pstart -> next = NULL;
              pstart -> ahead = NULL;

              if (abigerb(numa ,numb)>=1)
              times = (int)strlen(numa); //比較兩個(gè)字符串長(zhǎng)度,以大的作為循環(huán)次數(shù)
              else
                {
                  times = (int)strlen(numb);
                  pna = findend(numb); //交換指針
                  pnb = findend(numa);
                along=(int)strlen(numb); //標(biāo)記數(shù)字a的長(zhǎng)度;
                blong=(int)strlen(numa); //標(biāo)記數(shù)字b的長(zhǎng)度;
                }
                while ((times-- && (times>=0))|| carry != 0)
                {
                  if(!pstart->next) //如果當(dāng)前為空結(jié)點(diǎn),則申請(qǐng)新結(jié)點(diǎn)
                  {
                    pnew = new Node;
                    pnew -> data = 0;
                    pnew -> next = NULL;
                    pnew -> ahead = pstart;
                    pstart -> next = pnew;
                  }
                  else temp_result =(pstart->data +(*pna-48)+(*pnb-48)+carry) ; //自身的值+新值+進(jìn)位 作為當(dāng)前的新值

                  pstart -> data = temp_result%10; //存貯個(gè)位
                  carry = temp_result/10; //存貯進(jìn)位
                  pstart = pstart -> next; //結(jié)點(diǎn)移動(dòng)
                blong--;
                  if(blong>0)pnb--; //指針移向被加數(shù)高位
                  else *pnb=48; //之后相減就變?yōu)榱?不作任何運(yùn)算;
                  pna--; //加數(shù)指針移動(dòng),
                }
              pstart =head; //尋找鏈表的結(jié)尾點(diǎn)
              while(pstart->next != 0)
              {
              pstart->data += 48; //!!<<<因?yàn)槲覀兊妮敵鍪亲址K栽俅思由?8>>>> 逆順輸出
              pstart = pstart->next ;
              }

              int tip = 0; //轉(zhuǎn)為字符串用
                pstart = pstart->ahead ; //找有效字
                 //cout<<"\n結(jié)果是 : ";
                while(pstart != 0) //輸出正序的結(jié)果;
                {
                result[tip++] = pstart->data;
                 //cout< data;
                pstart = pstart->ahead ;
                }
                result[tip] = '\0';

              pstart =head; //釋放空間
              while(pstart->next != 0)
              {
              pnew = pstart->next ;delete pstart;
              pstart =pnew;
              }
              return ;
            }
            2.2 減法運(yùn)算的實(shí)現(xiàn)
                減法稍微有一點(diǎn)復(fù)雜, 因?yàn)闀?huì)處理負(fù)數(shù),而我們所用的是字符串的形式來(lái)保存數(shù)字也是為這一點(diǎn)。否則用整型或其它類型時(shí),則表示處理、保存時(shí)會(huì)相當(dāng)復(fù)雜。算法也是從低位開始減。先要判斷減數(shù)和被減數(shù)那一個(gè)位數(shù)長(zhǎng),減數(shù)位數(shù)長(zhǎng)是正常減;被減數(shù)位數(shù)長(zhǎng),則被減數(shù)減減數(shù),最后還要加上負(fù)號(hào);兩數(shù)位數(shù)長(zhǎng)度相等時(shí),最好比那一個(gè)數(shù)字大,否則負(fù)號(hào)處理會(huì)很繁瑣;處理每一項(xiàng)時(shí)要,如果前一位相減有借位,就先減去上一位的借位,無(wú)則不減,再去判斷是否能夠減開被減數(shù),如果減不開,就要借位后再去減,同時(shí)置借位為1,否則置借位為0。
                這有一我寫的比較兩個(gè)數(shù)字符串大小的函數(shù):
            //返回值說(shuō)明:0是alongblong ; 2是along=blong
            int abigerb(char *numa, char *numb) //比較兩個(gè)數(shù)最高位那一個(gè)大
            {
              int along=(int)strlen(numa); //標(biāo)記數(shù)字a的長(zhǎng)度;
              int blong=(int)strlen(numb); //標(biāo)記數(shù)字b的長(zhǎng)度;
              char *pna = numa; //指向數(shù)A的最高位,
              char *pnb = numb; //指向數(shù)B的最高位,
              if (along>blong) return 1;
              if (along==blong)
              {
                while(*pna) //比較兩個(gè)數(shù)那一個(gè)大
                {
                  if(*pna>*pnb)return 1;
                  else if(*pna<*pnb)return 0 ;
                  else if(*pna==*pnb){pna++;pnb++;} //1111與1112
                }
                return 2; //這表明找到最后了還是全相等;
              }
              return 0 ;
            }
                在程序時(shí)應(yīng)注意:
                1、如果被減數(shù)大于減數(shù)時(shí),指針和相應(yīng)循環(huán)長(zhǎng)度控制變量也要做相應(yīng)的修改。
                2、結(jié)果可能會(huì)出現(xiàn)前面是一堆0的情況,要處理好,如當(dāng)減數(shù)為11112,而被減數(shù)為11111時(shí),會(huì)出現(xiàn)00001,處理過(guò)程見代碼。
            /*--------------------------------------------------------------------------
            *函數(shù)名稱: 大數(shù)減法
            *函數(shù)過(guò)程:1 比較兩個(gè)數(shù)那一個(gè)長(zhǎng)
            * 2 以長(zhǎng)的作為循環(huán)次數(shù)
            * 3 如果兩個(gè)數(shù)長(zhǎng)度相等,從最高位開始比直到發(fā)現(xiàn)那一個(gè)數(shù)更大,使大項(xiàng)減去小項(xiàng)
            * 4 對(duì)應(yīng)項(xiàng)相減 進(jìn)位存貯直到下高位相加用
            * 5 每一位對(duì)應(yīng)項(xiàng)相減時(shí),處理三種可能的情況,a=b,ab;
            * 6 a=b時(shí),則計(jì)算,11-12,111-112,要考慮借位
            * 7 直到循環(huán)結(jié)束
            *入口參數(shù):numa,numb,result字符串
            *出口參數(shù):無(wú)
            *--------------------------------------------------------------------------*/

            void subtract(char *numa, char *numb,char *result)//計(jì)算減
                        {
                        char *pna = findend(numa);//指向numa的一個(gè)指針。point numa      pna 指向減數(shù)的最低位,
                        char *pnb = findend(numb);//指向numb的一個(gè)指針                 //pnb 指向被減數(shù)的最低位,
                        int  along=(int)strlen(numa);//標(biāo)記數(shù)字a的長(zhǎng)度;
                        int  blong=(int)strlen(numb);//標(biāo)記數(shù)字b的長(zhǎng)度;
                        int  times = 0;         // 標(biāo)記要計(jì)算多少次。
                        int  carry=0;           //存貯借位
                        int  clear0=0;          //消除結(jié)果最前面無(wú)用的'0'  13-5 = 08 的效果!!
                        int  isnegative=0;      //用來(lái)加上被減數(shù)大于減數(shù)時(shí)補(bǔ)上最后一個(gè)負(fù)號(hào)
                        Node *head,   // 用于存貯頭指針
                        *pstart,  // 用于存貯計(jì)算時(shí)的首指針
                        *pnew;    //作于申請(qǐng)新結(jié)點(diǎn)
                        head = pstart =new Node;//初始化首結(jié)點(diǎn)和頭結(jié)點(diǎn)。
                        pstart -> data = 0;
                        pstart -> next = NULL;
                        pstart -> ahead = NULL;
                        if (abigerb(numa ,numb))
                        times = strlen(numa);//比較兩個(gè)字符串長(zhǎng)度,以大的作為循環(huán)次數(shù)
                        else //交換位置以降低難度
                        {
                        times = strlen(numb);//讓數(shù)(字符串)長(zhǎng)的減去數(shù)(字符串)短的
                        pna = findend(numb);//交換指針
                        pnb = findend(numa);
                        along=(int)strlen(numb);//標(biāo)記數(shù)字a的長(zhǎng)度;
                        blong=(int)strlen(numa);//標(biāo)記數(shù)字b的長(zhǎng)度;
                        isnegative=1;//標(biāo)記最后要加上負(fù)號(hào)
                        }
                        while ((times-- && (times>=0))|| carry != 0)//carry != 0 說(shuō)沒有借位時(shí)
                        {
                        if(!pstart->next)//如果當(dāng)前為空結(jié)點(diǎn),則申請(qǐng)新結(jié)點(diǎn)
                        {
                        pnew = new Node;
                        pnew -> data = 0;
                        pnew -> next = NULL;
                        pnew -> ahead = pstart;
                        pstart -> next = pnew;
                        }
                        if(times<0)//如果計(jì)算完之后,借位等于1,,說(shuō)明必然為負(fù)值;
                        {
                        pstart -> data  = -3 ;//讓它等于負(fù)號(hào) '-'//-3來(lái)源于負(fù)號(hào)與0相差3。。                break;
                        }
                        else
                        {
                        if ( *pna == *pnb )//減數(shù)等于被減數(shù)時(shí)。結(jié)果等于直截相減的結(jié)果;并置借位為0
                        {
                        if(carry==0)pstart -> data = (*pna-48)-(*pnb-48); //111-11的情況
                        else
                        {
                        pstart->data = (*pna-48)-(*pnb-48)+10 -carry;//1121-1112
                        carry=1;
                        }
                        }
                        if( *pna > *pnb )//減數(shù)大于被減數(shù)時(shí)。結(jié)果等于直截相減的結(jié)果;并置借位為0
                        {
                        pstart -> data = (*pna-48)-(*pnb-48)-carry;  //存貯個(gè)位
                        carry=0;
                        }
                        else if( *pna < *pnb )//說(shuō)明被減數(shù)大于減數(shù),讓結(jié)果加10,相當(dāng)于借位 (carry)為1
                        {
                        if(times>0) pstart->data = (*pna-48)-(*pnb-48)+10 -carry;//13-5的情況作為新值
                        else  pstart->data = (*pnb-48)-(*pna-48) -carry; //3-5  作為當(dāng)前的新值
                        carry=1;
                        }
                        }
                        pstart = pstart -> next;          //結(jié)點(diǎn)移動(dòng)
                        blong--;
                        if(blong>0)pnb--;//指針移向被減數(shù)高位
                        else *pnb=48;//之后相減就變?yōu)榱?不作任何運(yùn)算,其實(shí)可以優(yōu)化的。但代碼會(huì)長(zhǎng)!而且還需要重新開結(jié)點(diǎn)。所以放棄;
                        pna--;//被數(shù)指針移動(dòng),
                        }
                        if(isnegative==1)////加上負(fù)號(hào)處理。增加一長(zhǎng)度并置為負(fù)號(hào)
                        {
                        pnew = new Node;
                        pnew -> data = 0;
                        pnew -> next = NULL;
                        pnew -> ahead = pstart;
                        pstart -> next = pnew;
                        pstart->data=-3;//因?yàn)閷ふ益湵淼慕Y(jié)尾點(diǎn)要統(tǒng)一加48。又因?yàn)?#8216;-’是45。所以等于‘-3’
                        }
                        pstart =head;//尋找鏈表的結(jié)尾點(diǎn)
                        while(pstart->next != 0)
                        {
                        pstart->data += 48;//!!<<<因?yàn)槲覀兊妮敵鍪亲址K栽俅思由?8>>>>  逆順輸出
                        pstart = pstart->next ;
                        }
                        int tip = 0;//轉(zhuǎn)為字符串用
                        clear0=0;//  消除結(jié)果最前面無(wú)用的'0'  13-5 = 08 的效果  ..>>修改字符串的首指針
                        pstart = pstart->ahead ;//找有效字
                        while(pstart != 0)//輸出正序的結(jié)果;
                        {
                        if (clear0==0 && ((int)pstart->data)==48&&pstart->ahead!=0)//  消除結(jié)果最前面無(wú)用的'0'
                        ;//不輸出任何東西
                        else
                        result[tip++] = pstart->data;
                        if(((int)pstart->data)!=48&&((int)pstart->data)!=45)clear0=1;//'-'號(hào)
                        pstart = pstart->ahead ;
                        }
                        result[tip] = '\0';
                        pstart =head;  //釋放空間
                        while(pstart->next != 0)
                        {
                        pnew = pstart->next ;delete pstart;
                        pstart =pnew;
                        }
                        return ;
                        }
                        


            2.3 乘法運(yùn)算的實(shí)現(xiàn)
                首先說(shuō)一下乘法計(jì)算的算法,從低位向高位乘,在豎式計(jì)算中,我們是將乘數(shù)第一位與被乘數(shù)的每一位相乘,記錄結(jié)果,之后,用第二位相乘,記錄結(jié)果并且左移一位,以此類推,直到計(jì)算完最后一位,再將各項(xiàng)結(jié)果相加。得出最后結(jié)果。當(dāng)然我們可以直接用這種方法,但要用多個(gè)鏈表來(lái)保存計(jì)算出的分結(jié)果, 之后結(jié)果再相加得到最后結(jié)果,但是這樣會(huì)浪費(fèi)很多空間,我們可以再優(yōu)化一下,就是只用一人鏈表來(lái)表示結(jié)果,先把第一位乘數(shù)與被乘數(shù)的結(jié)果保存在鏈表中,之后把存儲(chǔ)結(jié)果的頭部后移一位、也就是從鏈表的第二加起,當(dāng)?shù)诙怀藬?shù)與被乘數(shù)結(jié)果加到第二之后的各個(gè)項(xiàng)內(nèi)。以此類推,直到結(jié)束。這樣就可以用一個(gè)鏈表來(lái)存儲(chǔ)相乘后的結(jié)果。
                在程序時(shí)應(yīng)注意:
                1、傳入的乘數(shù)和被乘數(shù)是以字符串形式放入的話,要讓指針指向最后一位,我自己寫了個(gè)函數(shù)來(lái)完成這件事。鏈表傳入也要找到最后一向來(lái)計(jì)算;
                2、因?yàn)閭魅牒捅4娴亩际亲址杂?jì)算時(shí)要將字符轉(zhuǎn)化為數(shù)字,算完再轉(zhuǎn)化為字符存儲(chǔ);
                3、另外進(jìn)位時(shí)要處理,當(dāng)前的值加上進(jìn)位的值再看本位數(shù)字是否又有進(jìn)位;
                4、輸出時(shí)要逆序輸出,因?yàn)殒湵硎字羔樖谴娴慕Y(jié)果的最低位。我的函數(shù)為了對(duì)應(yīng)輸入輸出結(jié)果的一致性,都有采用了字符串輸出,所以在輸出時(shí)又將鏈表轉(zhuǎn)為了字符串。
                具體代碼如下:
            /*--------------------------------------------------------------------------
            *函數(shù)名稱: 大數(shù)乘法
            *函數(shù)過(guò)程:1 輸入兩個(gè)大數(shù)作為字符串
            * 2 作一個(gè)雙向鏈表
            * 3 兩個(gè)指針?lè)謩e指向數(shù)字字符串的最低位
            * 4 以第一個(gè)數(shù)的最低的一個(gè)位乘以第二個(gè)數(shù)的所有項(xiàng)存于鏈表中
            * 5 鏈表首指針移
            * 6 重復(fù)4,5依次從最低位乘到最高位
            * 7 乘完后因?yàn)樽畹臀皇擎湵硎祝詈笠晃皇擎湵砦病K栽谀骓樰敵鲦湵怼?br>* 4 直到循環(huán)結(jié)束
            *入口參數(shù):numa,numb,result字符串
            *出口參數(shù):無(wú)
            *--------------------------------------------------------------------------*/
            void multiply(char *numa, char *numb ,char *result)//用來(lái)儲(chǔ)結(jié)果的)//計(jì)算乘積
                        {
                        char *pna = findend(numa);//指向numa的一個(gè)指針。point numa      pna 指向乘數(shù)的最低位,
                        char *pnb = findend(numb);//指向numb的一個(gè)指針                 //pnb 指向被乘數(shù)的最低位,
                        int along=(int)strlen(numa);//標(biāo)記數(shù)字a的長(zhǎng)度;
                        int blong=(int)strlen(numb);//標(biāo)記數(shù)字b的長(zhǎng)度;
                        int  carry=0,temp_result;//存貯進(jìn)位  和臨時(shí)結(jié)果的
                        Node *head,   // 用于存貯頭指針
                        *pstart,  // 用于存貯計(jì)算時(shí)的首指針
                        *pnew,    //作于申請(qǐng)新結(jié)點(diǎn)
                        *pgo;     //作為每計(jì)算完一行時(shí),回到下一行起始節(jié)點(diǎn)用,移位標(biāo)致來(lái)用
                        head = pstart =new Node;//初始化首結(jié)點(diǎn)和頭結(jié)點(diǎn)。
                        pstart -> data = 0;
                        pstart -> next = NULL;
                        pstart -> ahead = NULL;
                        while (along--)
                        {
                        pgo = pstart;//保存進(jìn)位點(diǎn)
                        blong = (int)strlen(numb);//初始化長(zhǎng)度
                        pnb = findend(numb); //初始化指針
                        while ((blong-- && (blong>=0))|| carry != 0)
                        {
                        if(!pstart->next)//如果當(dāng)前為空結(jié)點(diǎn),則申請(qǐng)新結(jié)點(diǎn)
                        {
                        pnew = new Node;
                        pnew -> data = 0;
                        pnew -> next = NULL;
                        pnew -> ahead = pstart;
                        pstart -> next = pnew;
                        }
                        if(blong<0)temp_result = carry ;//處理只有進(jìn)位的情況
                        else temp_result =(pstart->data+(*pna-48)*(*pnb-48)+carry);//自身值+新值+進(jìn)位作為新值
                        pstart -> data = temp_result%10;  //存貯個(gè)位
                        carry = temp_result/10;           //存貯進(jìn)位
                        pstart = pstart -> next;          //結(jié)點(diǎn)移動(dòng)
                        pnb--; //指針移向被乘數(shù)高位
                        }
                        pstart = pgo->next; //前進(jìn)一個(gè)位置;
                        pna--;   //指針移向乘數(shù)高位
                        }
                        pstart =head;//尋找鏈表的結(jié)尾點(diǎn)
                        while(pstart->next != 0)
                        {
                        pstart->data += 48;//!!<<<因?yàn)槲覀兊妮敵鍪亲址K栽俅思由?8>>>>  逆順輸出
                        pstart = pstart->next ;
                        }
                        int tip = 0;//轉(zhuǎn)為字符串用
                        pstart = pstart->ahead ;//找有效字
                        while(pstart != 0)//輸出正序的結(jié)果;
                        {
                        result[tip++] = pstart->data;
                        pstart = pstart->ahead ;
                        }
                        result[tip] = '\0';
                        pstart =head;  //釋放空間
                        while(pstart->next != 0)
                        {
                        pnew = pstart->next ;delete pstart;
                        pstart =pnew;
                        }
                        return ;
                        }
                        


            2.4 除法運(yùn)算的實(shí)現(xiàn)
                首先說(shuō)一下我們所要的結(jié)果,當(dāng)除數(shù)除不開被子除數(shù)時(shí),不用除到小數(shù),當(dāng)除數(shù)小于被除數(shù)時(shí),除數(shù)作為余數(shù)既可,不用再向下除了。
                除法算法是最容易想到的啦!我們學(xué)數(shù)字電路,或模擬電路時(shí)里面有用門實(shí)現(xiàn)的除法器,做法是用除數(shù)減被除數(shù),再用一個(gè)加法器去計(jì)算存儲(chǔ)結(jié)果,算法簡(jiǎn)單明了,結(jié)果我實(shí)現(xiàn)之后,計(jì)算速度大大出乎我的遇料,比算乘方時(shí)還慢,經(jīng)仔細(xì)想想電路中計(jì)算的長(zhǎng)度不過(guò)8位,16位,32位,而且都是硬件實(shí)現(xiàn),我們要算的是幾千位,幾萬(wàn)位。特別是兩數(shù)位長(zhǎng)度差很大時(shí)計(jì)算速度相當(dāng)慢,如10000-3時(shí)要進(jìn)行多少次鏈表運(yùn)算啊。
                否定了這條算法,經(jīng)不斷思考,發(fā)現(xiàn)另一種方法可行,且效率僅次于減法。就是從高位向低位減,減時(shí)以被除數(shù)長(zhǎng)度為單位,從高位取出大于被除數(shù)的字符串,和被除數(shù)相減,減的次數(shù)為結(jié)果,余數(shù)從剩下的除數(shù)高位再取出幾位做補(bǔ)位,直到大于被除數(shù)。再減,循環(huán)減到被減數(shù)大于余數(shù)加上補(bǔ)位,那么這個(gè)新的余數(shù)作為結(jié)果返回。
                在程序時(shí)應(yīng)注意:
                1、除法算法計(jì)算時(shí)是用的最高位開始向低位減,所以要注意指針的位置。
                2、余數(shù)和被減數(shù)相減時(shí),一定要注意:一旦能夠減開被除數(shù)時(shí),一定要每從除數(shù)那里取一個(gè)字符時(shí),結(jié)果也要對(duì)應(yīng)補(bǔ)一個(gè)0。如111222/111。
            /*--------------------------------------------------------------------------
            *函數(shù)名稱: 大數(shù)除法2--
            *函數(shù)想法:1 用指針指向除數(shù)的最高位,保存臨時(shí)字符串; tempstr[a++] = pna
            * 2 如果臨時(shí)字符串大于被除數(shù),則相減。結(jié)果等于余數(shù)
            * if(tempstr>numb)tempstr = tempstr - numb
            * 3 如果小于被除數(shù)且指針到頭,余數(shù) 等于 臨時(shí)字符串
            * if(tempstr *
            *入口參數(shù):numa,numb,result,remainder字符串
            *出口參數(shù):無(wú)
            *--------------------------------------------------------------------------*/
            void divide2( char *numa, char *numb,char *result,char *remainder)//計(jì)算除法2
                        {
                        char one[]="1";//臨時(shí)字符串....
                        char one2[]="1";//
                        char zero[]="0";//
                        char numb2[6048];//
                        char tempstr[6018]="";//臨時(shí)字符串
                        int  ia=0,ia2=0;//tempstr的指示器
                        bool  moveon=false;//翻轉(zhuǎn)牌
                        char *pna = numa;//指向numa的一個(gè)指針。point numa      pna 指向減數(shù)的最低位,
                        char *pnb = findend(numb);//指向numb的一個(gè)指針                 //pnb 指向被減數(shù)的最低位,
                        Node *head,   // 用于存貯頭指針
                        *pstart,  // 用于存貯計(jì)算時(shí)的首指針
                        *pnew;    //作于申請(qǐng)新結(jié)點(diǎn)
                        head = pstart =new Node;//初始化首結(jié)點(diǎn)和頭結(jié)點(diǎn)。
                        pstart -> data = 0;
                        pstart -> next = NULL;
                        pstart -> ahead = NULL;
                        moveon = false;
                        while(*pna)
                        {
                        if(!pstart->next)//如果當(dāng)前為空結(jié)點(diǎn),則申請(qǐng)新結(jié)點(diǎn)
                        {
                        pnew = new Node;
                        pnew -> data = 0;
                        pnew -> next = NULL;
                        pnew -> ahead = pstart;
                        pstart -> next = pnew;
                        }
                        ia=(int)strlen(tempstr);//取的長(zhǎng)度
                        tempstr[ia++] = *(pna++);
                        tempstr[ia] ='\0'; //轉(zhuǎn)換為字符串
                        if(tempstr[0]=='0')//處理高位也是0的那種 如00
                        {
                        ia2=0;
                        while(tempstr[ia2]=='0')++ia2;
                        while(ia2>=1)//清除無(wú)用的0
                        {
                        ia=ia2-1;
                        tempstr[ia]=tempstr[ia2];
                        --ia2;
                        }
                        tempstr[++ia2]='\0';
                        }
                        while(abigerb(tempstr,numb)>0)//如果tempstr大于等于numb
                        {
                        if(tempstr[0]=='0')//處理高位也是0的那種 如00----此乃冗余代碼,留做記念用
                        {
                        ia2=0;
                        while(tempstr[ia2]=='0')++ia2;
                        if(ia==ia2 )
                        {
                        moveon = true;
                        break;
                        }
                        }
                        strcpy(numb2,numb);
                        subtract(tempstr, numb,tempstr);//A-B
                        strcpy(numb,numb2);
                        if(tempstr[0]=='-')//若判斷的不準(zhǔn),變?yōu)榱素?fù)數(shù)就再加上B。。
                        {
                        strcpy(numb2,numb);
                        addition(tempstr, numb,tempstr);//A-B
                        strcpy(numb,numb2);
                        ia2=0; //修正之后的長(zhǎng)度。因?yàn)榧臃ㄖ形醋鲐?fù)數(shù)運(yùn)算
                        ia=0;  //為了消除最后的那一個(gè)負(fù)號(hào),整體向前移動(dòng)。
                        while(tempstr[ia2]!='\0')++ia2;
                        while(ia2>=1)//清除無(wú)用的0
                        {
                        tempstr[ia]=tempstr[ia+1];
                        ++ia;
                        --ia2;
                        }
                        tempstr[ia]='\0';
                        moveon = true;
                        break;
                        }
                        pstart->data++ ; //結(jié)果自加
                        moveon = true;
                        }
                        if(moveon) pstart = pstart -> next;          //結(jié)點(diǎn)移動(dòng)
                        }
                        strcpy(remainder,tempstr);//存貯余數(shù)
                        int tip = 0;//轉(zhuǎn)為字符串用
                        pstart =head;//尋找鏈表的結(jié)尾點(diǎn)
                        while(pstart->next != 0)
                        {
                        pstart->data += 48;//!!<<<因?yàn)槲覀兊妮敵鍪亲址K栽俅思由?8>>>>  逆順輸出
                        result[tip++] = pstart->data;
                        pstart = pstart->next ;
                        }
                        result[tip] = '\0';//存貯結(jié)果
                        pstart =head;  //釋放空間
                        while(pstart->next != 0)
                        {
                        pnew = pstart->next ;delete pstart;
                        pstart =pnew;
                        }
                        return ;
                        }
                        


            2.5 冪運(yùn)算的實(shí)現(xiàn)
                冪的實(shí)現(xiàn)是最為簡(jiǎn)單的了,國(guó)為有了前面的算法做鋪墊,就是調(diào)用乘法函數(shù),來(lái)循環(huán)去自乘,冪指數(shù)相應(yīng)減1,直到冪指數(shù)變?yōu)?時(shí)結(jié)束。其詳細(xì)代碼如下:

            /*--------------------------------------------------------------------------
            *函數(shù)名稱: 大數(shù)冪
            *函數(shù)想法:1 B自減1直到,,作為循環(huán)控制變量.保存結(jié)果;
            * 2 結(jié)果初值1 每次乘以A
            * 3 重復(fù)1、2步驟到結(jié)束.
            *入口參數(shù):numa,numb,result字符串
            *出口參數(shù):無(wú)
            *--------------------------------------------------------------------------*/

            void power (char *numa, char *numb,char *result) //計(jì)算冪
            { char one[]="1"; //臨時(shí)字符串....
            char one2[]="1";
            char zero[]="0";
            char numb2[6048];
            char remainder[6048];
            strcpy(result,one); //給結(jié)果初值為1
            strcpy(numb2,numb);

            subtract(numb,one ,remainder); //B自減1
            strcpy(numb,numb2);

            strcpy(numb2,numb);
            multiply(result,numa,result ); //A自己乘自己
            strcpy(numb,numb2);

            while(strcmp(remainder,zero)>0) //A大于相等B時(shí) 就是numb不等于0時(shí)
            {
            strcpy(numb2,numb);
            multiply(result,numa,result ); //A自己乘自己
            strcpy(numb,numb2);
            strcpy(one,one2);
            subtract(remainder,one ,remainder); //B減一
            }

            return ;
            }

             

            3. 程序運(yùn)行介面
                程序的介面制作就不多加描述了,以下是我的大數(shù)程序的運(yùn)行介面。


            4. 總結(jié)與評(píng)價(jià)
                1) 本文主旨是對(duì)算法加以了實(shí)現(xiàn),但未做相應(yīng)的優(yōu)化。因?yàn)楸疚牡哪康厥菍?duì)大數(shù)運(yùn)算的過(guò)程產(chǎn)生一個(gè)具體設(shè)計(jì)方法與實(shí)現(xiàn)思路。而還是不是工程上能所直接應(yīng)用的。當(dāng)然在要作中是也許用的設(shè)計(jì)語(yǔ)言并不是C語(yǔ)言,可能是JAVA、 C++、 Delphi 、PHP等等。但不管是什么樣的設(shè)計(jì)語(yǔ)言,設(shè)計(jì)思路都是相同的。
                2) 關(guān)于代碼和算法優(yōu)化問(wèn)題,本文中代碼并不是簡(jiǎn)短,高效。現(xiàn)在對(duì)此說(shuō)明個(gè)人認(rèn)為在工程要改正的幾個(gè)方面。首先每個(gè)鏈表節(jié)點(diǎn)的元素所存的數(shù)據(jù)小的可憐,只存儲(chǔ)了一位數(shù)據(jù),但這是最容易想到的,模仿十進(jìn)制那樣進(jìn)位。但這并沒考慮機(jī)器的計(jì)算的情況,在我們常用的32位計(jì)算中,CPU中加減乘除的一次運(yùn)算是32位的值,也就是說(shuō)2的32次方的一個(gè)值,這就是說(shuō)1加上1的CPU工作量和小于2的32的兩位數(shù)相加是用的相同的周期。如下圖所示:
                為避免運(yùn)算結(jié)果大于2的32次,因?yàn)榇笥诘脑捰謺?huì)造成一次CPU周期運(yùn)算,但這樣當(dāng)然也可以做。但建議用下面方法,考慮乘法的原因,兩個(gè)2的16次方相乘就是2的32次方的情況,所以我們可以定義每個(gè)鏈表節(jié)點(diǎn)值為2的16次方,也就是 18446744073709551616的一個(gè)整數(shù)值,C++語(yǔ)言中_int64類型的范圍就是這么大。再把它當(dāng)作以前處理十進(jìn)制的權(quán)10去處理,效率會(huì)翻2的16方倍了。結(jié)點(diǎn)數(shù)巨減,主要是開內(nèi)存方面,有了極大的減少。
                3) 另外本程序中是用數(shù)組去傳遞參數(shù)的,這非常不好,而且會(huì)限制你結(jié)果的長(zhǎng)度。只有一點(diǎn)好處,易懂!個(gè)人認(rèn)為工程中,一定要用鏈表指針來(lái)傳遞參數(shù), 這樣就解決了可算到無(wú)限長(zhǎng)的問(wèn)題。只是釋放鏈表時(shí)要在最后用完再釋放了。對(duì)于本文用的方法就顯得明了多了。
                4) 總體來(lái)說(shuō)本文重在說(shuō)明方法,效率較差。工作時(shí)定要注重效率問(wèn)題。在C++系列下的程序盡量多用庫(kù)函數(shù),會(huì)減少大量的代碼。適當(dāng)?shù)娜ゼ尤胄﹨R編以提高效率。

             

            5. 軟件下載演示
            點(diǎn)擊下載大數(shù)運(yùn)算軟件

            6. 參考文獻(xiàn)
            1. 李藝《網(wǎng)絡(luò)安全講義》PPT文檔
            2. 譚浩強(qiáng)《C程序設(shè)計(jì)》第二版,清華大學(xué)出版社
            3. Adam Drozdek《數(shù)據(jù)結(jié)構(gòu)與算法》第三版,清華大學(xué)出版社
            4. 何德全《網(wǎng)絡(luò)安全》清華大學(xué)出版社
            5. http://www.tup.com.cn

            posted on 2007-08-15 13:21 葉子 閱讀(13615) 評(píng)論(8)  編輯 收藏 引用 所屬分類: C\C++

            Feedback

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2007-10-29 09:29 Sailing

            學(xué)習(xí)了哦  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2007-12-24 00:37 秦歌

            好東西,學(xué)習(xí)了  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2009-08-09 13:43 大牛

            你的大數(shù)加法有點(diǎn)問(wèn)題  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2009-08-10 19:27 葉子

            @大牛
            啥問(wèn)題?說(shuō)說(shuō)  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2010-02-15 08:20 BJ.Paul


            怎么說(shuō)呢?


            主要在效率方面;

            用struct 來(lái)規(guī)劃表達(dá)大數(shù),未免將雙鏈表用的不是地方,

            首先,操作大數(shù)不方便;
            其次,效率不是很高;


            就說(shuō)加法吧,需要那么多語(yǔ)句來(lái)完成一個(gè)簡(jiǎn)單的加法,
            實(shí)在怪異的很;

            大數(shù)中, 1,0,-1,是極其常用常數(shù),沒有統(tǒng)一的表達(dá);


            這樣的解決方案,要比openssl的解決方案慢許多。

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

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2010-02-22 02:35 OpenHero

            把char修改成int32,性能會(huì)更高:)  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2011-06-11 16:31 coaku

            對(duì),LZ你的加法有問(wèn)題,字符串指針指錯(cuò)了,其他還沒看  回復(fù)  更多評(píng)論   

            # re: 大數(shù)四則運(yùn)算的C++實(shí)現(xiàn) 2011-11-26 17:31 someone

            乘法你沒有考慮當(dāng)兩個(gè)數(shù)的位數(shù)非常多時(shí),加法導(dǎo)致整數(shù)溢出問(wèn)題  回復(fù)  更多評(píng)論   

            av无码久久久久久不卡网站| 一本大道久久香蕉成人网| 色欲综合久久中文字幕网| 777久久精品一区二区三区无码| 亚洲人成无码久久电影网站| 久久久久久国产精品美女| 久久精品国产99久久久香蕉| 久久A级毛片免费观看| 久久人人爽人人爽人人片av麻烦| 亚洲αv久久久噜噜噜噜噜| 韩国三级大全久久网站| 久久国产精品无码一区二区三区 | 国内精品久久久久影院一蜜桃 | 国产免费久久久久久无码| 久久久久99精品成人片欧美| 国产精品99久久精品爆乳| 伊人久久大香线蕉综合Av| 一本一本久久aa综合精品| 国产综合久久久久| 思思久久精品在热线热| 思思久久99热只有频精品66| 精品久久人人爽天天玩人人妻| 欧美777精品久久久久网| 99久久精品这里只有精品| 国产成年无码久久久免费| 手机看片久久高清国产日韩| 天堂无码久久综合东京热| 久久精品国产一区| 久久国产亚洲高清观看| 国产亚洲精久久久久久无码77777 国产亚洲精品久久久久秋霞 | AV无码久久久久不卡蜜桃| 老男人久久青草av高清| 欧美伊人久久大香线蕉综合69| 亚洲午夜久久久精品影院 | 国产精品久久久久久久久软件| 激情久久久久久久久久| 亚洲欧美日韩精品久久| 国产精品成人99久久久久91gav| 狠狠色婷婷综合天天久久丁香| 国产精品久久久久AV福利动漫| 欧美午夜精品久久久久免费视|