大整數(shù)運(yùn)算

大整數(shù)運(yùn)算

大整數(shù)存儲(chǔ)

在C語(yǔ)言中若要計(jì)算A+B,如果A和B的在范圍int(或long)范圍內(nèi),那很容易就可以寫(xiě)出來(lái),但是若A和B是有著1000個(gè)位數(shù)的整數(shù)就沒(méi)辦法用數(shù)據(jù)類(lèi)型來(lái)表示了,這時(shí)只能去模擬加減乘除的運(yùn)算過(guò)程。此外,大整數(shù)又稱(chēng)高精度整數(shù),其含義就是用基本數(shù)據(jù)類(lèi)型無(wú)法存儲(chǔ)其精度的整數(shù)。

若要計(jì)算大整數(shù)首先要先把需要計(jì)算的大整數(shù)存儲(chǔ)下來(lái),對(duì)于存儲(chǔ)大整數(shù)使用數(shù)據(jù)即可,例如定義int型數(shù)組d[1000],那么這個(gè)數(shù)組中的一位就代表整數(shù)的每一位,不過(guò)這就產(chǎn)生一個(gè)問(wèn)題,當(dāng)我們把整數(shù)例如:258369當(dāng)字符串用%s讀入數(shù)組S時(shí),則S[0]=2,S[1]=5,S[2]=8……S[5]=9此時(shí)若兩數(shù)相加需要進(jìn)位則需要數(shù)組集體向后移一位才可以進(jìn)位十分麻煩,所以我們將讀入之后需將數(shù)組翻轉(zhuǎn)一下及:S[0]=9,S[1]=6,S[2]=3……S[5]=2

而為了方便獲取大整數(shù)我們首先定義一個(gè)int類(lèi)型的變量len來(lái)記錄大整數(shù)的長(zhǎng)度,并和數(shù)組 d 組合成結(jié)構(gòu)體并利用構(gòu)造函數(shù)為結(jié)構(gòu)體初始化,代碼如下

struct bign{
    int d[1000];                 //定義數(shù)組用來(lái)存儲(chǔ)大整數(shù)
    int len;                     //用來(lái)存儲(chǔ)大整數(shù)的位數(shù)
    bign(){
        memset(d, 0, sizeof(d)); //初始化數(shù)據(jù)b全部存儲(chǔ)為0
        len = 0;                 //初始化大整數(shù)長(zhǎng)度
    }
};

而輸入大整數(shù)時(shí),一般先用字符串讀入,然后再把字符串另存為bing結(jié)構(gòu)體,由于使用 char 數(shù)組讀入,所以要將翻轉(zhuǎn)一下然后在賦值給結(jié)構(gòu)體中的 d數(shù)組:

bign change(shar str[]){  //將大整數(shù)存入bign
    bign a;
    int i;
    a.len = strlen(str);   //bign的長(zhǎng)度就是字符串的長(zhǎng)度
    for(i = 0; i < a.len; i++)
        a.d[i] = str[a.len - i -1] - '0';   //逆著賦值
    return a;
}

若需要比較兩個(gè)大整數(shù)的大小,則首先判斷兩者的len大小,如果不相等,則len長(zhǎng)的大;如果相等,則從高位到低位一次比較,直到某一位不等時(shí)就可以判斷出兩數(shù)的大小,代碼如下:

int compare(bign a, bign b){   //比較a和b的大小
    if(a.len > b.len) return 1;   //a大返回 1
    else if(a.len < b.len) return -1;  //b大返回 -1
    else{
        int i;
        for(i = a.len - 1; i >= 0; i--){
            if(a.d[i] > b.d[i]) return 1;       //a大返回 1
            else if(a.b[i] < b.d[i]) return -1; //b大返回 -1
        }
        return 0;  //兩數(shù)相等返回 0
    }
}

大整數(shù)的四則運(yùn)算

高精度加法

若將153+86看做兩個(gè)大整數(shù)相加,我按照小學(xué)的豎式進(jìn)行相加如下:

高精度加法
  1. 3 + 6 = 9,個(gè)位取作為該結(jié)果 9 ,十位取 0作為進(jìn)位。
  2. 5 + 8 = 13,再加上進(jìn)位0還為13,然后個(gè)位取3作為結(jié)果,十位1作為進(jìn)位。
  3. 1 + 0 = 1 ,再加上進(jìn)位1,然后取個(gè)位2為結(jié)果

將上述步驟歸納可得出如下代碼:

bign add(bign a, bign b){   //高精度a+b
    bign c;
    int carry = 0;    //表示進(jìn)位
    int i;
    for(i = 0; i<a.len || i<b.len; i++){ //以較長(zhǎng)的為界限
        int temp = a.d[i] + b.len[i] + carry;   //兩數(shù)相加并加上進(jìn)位
        c.d[c.len++] = temp % 10;   //個(gè)位為該位結(jié)果
        carry = temp / 10;      //十位為進(jìn)位
    }
    if(carry !=0 ) c.d[c,len++] = carry;    //軟工最后進(jìn)位不為零則直接賦值給最高位
    return c;
}

完整高精度A+B代碼如下:

#include<stdio.h>
struct bign{
    int d[1000];                 //定義數(shù)組用來(lái)存儲(chǔ)大整數(shù)
    int len;                     //用來(lái)存儲(chǔ)大整數(shù)的位數(shù)
    bign(){
        memset(d, 0, sizeof(d)); //初始化數(shù)據(jù)b全部存儲(chǔ)為0
        len = 0;                 //初始化大整數(shù)長(zhǎng)度
    }
};
bign change(shar str[]){  //將大整數(shù)存入bign
    bign a;
    int i;
    a.len = strlen(str);   //bign的長(zhǎng)度就是字符串的長(zhǎng)度
    for(i = 0; i < a.len; i++)
        a.d[i] = str[a.len - i -1] - '0';   //逆著賦值
    return a;
}
bign add(bign a, bign b){   //高精度a+b
    bign c;
    int carry = 0;    //表示進(jìn)位
    int i;
    for(i = 0; i<a.len || i<b.len; i++){ //以較長(zhǎng)的為界限
        int temp = a.d[i] + b.len[i] + carry;   //兩數(shù)相加并加上進(jìn)位
        c.d[c.len++] = temp % 10;   //個(gè)位為該位結(jié)果
        carry = temp / 10;      //十位為進(jìn)位
    }
    if(carry !=0 ) c.d[c,len++] = carry;    //軟工最后進(jìn)位不為零則直接賦值給最高位
    return c;
}
void print(bign a){    //輸出bign
    int i;
    for(i = a.len-1; i >=0; i--)
        printf("%d",a.d[i]);
}

main()
{
    char s1[1000],s2[1000];
    scanf("%s%s",s1,s2);
    bign a = change(s1);
    bign b = change(s2);
    print(add(a,b));
}

高精度減法

若將 169-96 看做兩個(gè)大整數(shù)減法,我按照小學(xué)的豎式進(jìn)行相加如下:

減法
  1. 9-6>0夠減,不需要借位,則直接減,結(jié)果為:3
  2. 6-9<0不夠減,向高位11,于是改結(jié)果為16-9=7
  3. 兩數(shù)最高位均為0,計(jì)算結(jié)束

將上述步驟歸納可得出如下代碼:

bign sub(bign a,bign b){   //高精度A-B
    bign c;
    int i;
    for(i = 0; i<a.len || i<b.len; i++){ //以較長(zhǎng)的為界限
        if(a.d[i] < b.d[i]){   //如果不夠減
            a.d[i+1] --;       //向高位借位
            a.d[i] += 10;      //當(dāng)前位+10
        }
        c.d[c.len++] = a.[i] - b.d[i];   //計(jì)算當(dāng)前結(jié)果
    }
    while(c.len-1 >= 1 && c.d[c.len -1] == 0)
        c.len -- ;          //去除高位的0,同時(shí)若兩數(shù)相見(jiàn)為0則保留一位0
    return c;
}

若題目涉及的高精度減法A-B<0則利用函數(shù)compare()判斷一下,若 A<B 則計(jì)算 B-A 并輸出一個(gè)符號(hào)即可。

高精度與低精度的乘法

所謂低精度就是可以用基本數(shù)據(jù)類(lèi)型存儲(chǔ)的數(shù)據(jù),而高精度與低精度的乘法就是講述 bign 與 int 類(lèi)型的乘法,其做法與小學(xué)學(xué)的豎式略有不同,若以258 × 25(258看做高精度數(shù)據(jù)、25看做低精度數(shù)據(jù))為例,在計(jì)算過(guò)程中要把低精度數(shù)據(jù)25看做一個(gè)整體,具體做法如下:

乘法
  1. 25×8=200,個(gè)位數(shù) 0 作為該位的結(jié)果,20 作為進(jìn)位。
  2. 25×5=125,再加上進(jìn)位的 20,結(jié)果為145,個(gè)位數(shù) 5 作為該位結(jié)果,14作為進(jìn)位。
  3. 2×25=50,再加上進(jìn)位的 14,結(jié)果為64,個(gè)位數(shù) 4 作為該位結(jié)果,6作為進(jìn)位。

將上述步驟歸納可得出如下代碼:

bign multi(bign a,bign b){
    bign c;
    int carry = 0;       //進(jìn)位
    int i;
    for(i = 0; i < a.len; i++){
        int temp = a.d[i] * b + carry;
        c.d[c.len++] = temp % 10;   //個(gè)位為該位結(jié)果
        carry = temp / 10;      //十位為進(jìn)位
    }
    while(carry !=0 ){   //乘法的進(jìn)位和加法不一樣,乘法的可能不止一一位
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}

高精度除以低精度

除法計(jì)算和小學(xué)學(xué)的豎式相同,以 1234/7 為例:

除法
  1. 1與7比較,不夠除,因此該位商為0,余數(shù)為1。
  2. 余數(shù)1與新位2組合成12,12與7比較,夠除,商為1,余數(shù)為5。
  3. 余數(shù)5與新位3組合成53,53與7比較,夠除,商為7,余數(shù)為4。
  4. 余數(shù)4與新位4組合成44,44與7比較,夠除,商為6,余數(shù)為2。

將上述步驟歸納可得出如下代碼:

bign divde(bign a, bign b, int& r){     //r為余數(shù)
    bign c;
    c.len = a.len;         //被除數(shù)的每一位和商的每一位是一一對(duì)應(yīng)的,因此先另長(zhǎng)度相等
    int i;
    for(i = a.len - 1; i >=0 ; i--){      //從高位開(kāi)始除
        r = r * 10 + a.d[i];              //和上一位遺留的余數(shù)組合
        if(r < b) c.d[i] = 0;             //不夠除則為0
        else{
            c.d[i] = r / b ;         //夠除則求出商
            r %= b;                  //獲得新的余數(shù)
        }
    }
    while(c.len -1 >= 1 && c.d[c.len - 1] == 0)
        c.len --;          //去除高位的0,同時(shí)若兩數(shù)相見(jiàn)為0則保留一位0
    return c;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、定義、賦值、比較、輸出1、大整數(shù)的結(jié)構(gòu)體 2、逆著賦值(先用字符串讀入,再把字符串另存值bign結(jié)構(gòu)體)思想:...
    km15閱讀 50評(píng)論 0 0
  • 大整數(shù)的存儲(chǔ) 定義結(jié)構(gòu)體,用int數(shù)組d[]存儲(chǔ),整數(shù)的高位存在數(shù)組的高位,整數(shù)的低位存儲(chǔ)在數(shù)組的低位。因?yàn)樵谶M(jìn)行...
    1nvad3r閱讀 326評(píng)論 0 0
  • 1023 Have Fun with Numbers (20分) 分析: 使用高精度乘法模板進(jìn)行乘2操作,再使用一...
    1nvad3r閱讀 235評(píng)論 0 0
  • 一、大數(shù)字運(yùn)算 在 Java 中提供了大數(shù)字的操作類(lèi),即 java.math.BigInteger 類(lèi)與 jav...
    編程鴨閱讀 536評(píng)論 0 0
  • 之前早就想把學(xué)過(guò)的算法記錄下來(lái),但是一直沒(méi)有時(shí)間。最近在給五年級(jí)的小學(xué)生上OI的算法課,所以正好可以把所思所想留存...
    flydan閱讀 1,088評(píng)論 0 0

友情鏈接更多精彩內(nèi)容