1. 程式人生 > >小專案:大數的基本運算

小專案:大數的基本運算

大數運算

開發環境Visual Studio 2015

主要技術string,C++類

專案描述

1.對於計算機不能進行計算的大資料進行處理,讓計算機實現大資料的讀入、輸出和基本運算;

2.使用C++類將超過內建型別(long long int)範圍的數轉換成字串進行儲存,並將儲存大數的字串拆開進行分析,逐位進行運算儲存,即將大數問題分解成單個字元的相互運算;

3.實現大數的讀入,輸出以及大數的加,減,乘,除運算功能。

大數運算的實現方法主要有以下幾種:

(1) 用字串表示大數。將大數用十進位制字元陣列表示,然後按照“豎式計算”的思想進行計算。這種方法比較容易理解,但是計算效率很低。

(2)將大數看成二進位制流進行處理。使用各種位運算和邏輯操作來實現大數的運算。該方法設計複雜,可讀性較差,而且難以除錯。

(3)將大數表示成一個n進位制陣列。n的取值越大,陣列的大小越小,這樣可以縮短運算的時間及空間複雜度,提高演算法的效率。在32位系統中,n可以取2^32,這時每一位的取值範圍是0~0xffffffff

    這裡考慮用方法(3)來實現,n=2^32時,大數的每一位恰好是unsigned long 的範圍,考慮到加法和乘法中進位時的溢位現象不好判斷,可以選取long long型,並且對於每個大數,包含一個變數表示其符號,一個變數來表示其長度,一個數組來儲存每一位的值。於是,可以用下面結構體表示一個大數:

typedef struct LargeNumber
{
    bool tag;                          // 標誌大數的符號 true:正數 ,false :負數
    int length;                         // 記錄大數的長度
    long long bigInt[SIZE];              // 記錄大數各位的值
 
    LargeNumber( const bool& t=true,const int& len=0)
    {
        tag = t;
        length = len;
 
        for( int i=0; i<SIZE; ++i )
        {
            bigInt[i]= 0;
        }
    }
};

一、大數加法

   假設在加法中兩個運算元都是大於0的。按照“豎式計算”的思想,首先將兩運算元低位對齊,然後從最低位開始按“位”相加,當“位”相加的結果大於2^32-1時做進位處理(carry=1),否則不進位(carry=0)。


符號演示:op1=ABCD, op2=EFG

    A  B  C  D

    +  E  F  G

-------------------

H  I  J  K   L

   初始化carry=0,其中若D+G+carry>0xffffffffL=D+G+carry-0xffffffff-1, carry=1;L=D+G+carrycarry=0按照上述方法計算K,J,I,H。

例如:0x1  0x1  0x1  + 0xffffffff 0xffffffff; 初始carry=0

運算過程:

(1)0x1+0xffffffff+0>0xffffffff, 所以計算結果的最低位result.bigInt[0]=0x0,carry=1;

(2)0x1+0xffffffff+1>0xffffffff,所以result.bigInt[1]= 0x1+0xffffffff+1-0xffffffff-1=1,carry=1;

(3)0x1+1<0xffffffff,所以result.bigInt[2]=2;result.length=2;

最終結果為2  1  0

二、大數減法

   為了簡化計算,假設被減數總是不小於減數,這樣計算的最終結果總是大於等於0。基本思路和大數加法基本一致,減法中可能需要借位,定義並初始借位變數borrow=0。顯然,borrow要麼等於0,要麼等於1

 

例如:0x1 0x1 0x1 – 0xffffffff  0xffffffff;初始borrow=0

計算過程:

(1) 0x1<0xfffffff+borrow,這時需要借位,result.bigInt[0]= 0xffffffff-(0xffffffff+0-0x1)+1=2,borrow=1;

(2)0x1<0xffffffff+borrow,於是result.bigInt[1]= 0xffffffff-(0xffffffff+1-0x1)+1=1,borrow=1;

(3)0x1=0+borrow,於是result.bigInt[2]=0, borrow=0;

最終結果為:1  2

三、大數乘法

   假設乘法的兩個運算元均為正數。按照“豎式計算”的思想,大數的乘法可以藉助大數的加法,用乘數的每一位乘以被乘數,然後將每一次的計算結果相加。在每位相乘的過程中依然存在進位現象,而且此時進位不只是1,還存在更大的數。

 

過程演示:

        A   B

  *    C   D

---------------

       E  F G

+ H  I  J

----------------------------

K M N  O P

      其中,B*D+carry>0xffffffff,那麼進位G=(B*D+carry)%0xffffffffcarry=(B*D+carry)/0xffffffff;

否則,G=B*D+carry,carry=0;按照上述計算原則計算,F E J I H.並按照大數加法的計算方法計算P O N M K

例如: 0x1  0x1  0x1 * 0xffffffff  0xffffffff。

計算過程:

10x1 0x1 0x1 * 0xffffffff =0xffffffff 0xffffffff 0xffffffff

20x1 0x1 0x1 * 0xffffffff =0xffffffff 0xffffffff 0xffffffff,由於這是乘數的第一位,所以結果“擴充套件一位”,變成0xffffffff 0xffffffff 0xffffffff 0x0

3)計算0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0x0

4)結果為1 0 0xffffffff 0xfffffffe 0xffffffff

四、大數除法 

  除法建立在乘法的基礎上,迴圈搜尋num使得num*op1==op2,效率較低。

 

執行結果: