c語言 大數加法、階乘和乘法


一.大數加法

定義兩個足夠大的數字,其數值遠超過long的取值范圍,設該大數的位數有兩百位,求其相加所得

大數加法的核心思想詳見此鏈接,內有詳細的動畫演示,這里不再贅述

大數加法、大數階乘

直接上代碼:

#include<string.h>
#include<stdio.h>
#define N 10//定義當前一個足夠大的數字為10位,可任意更改
void print_num(int a[],int n)
{
    int i=n-1;//從逆序數組的最后一項開始查找,進行反逆序
    while(a[i]==0)//由於規定的數組比真實計算的數字大,所以數組最后幾位必定存在0的情況
        --i;//這種情況下一定要將0舍去,否則會抬高數組的位數
    for(;i>=0;i--)//找到非零的數組,進行反逆序輸出
        printf("%d",a[i]);
}
void plus(int num1[],int num2[],int n)
{//尤其注意!由於數組是逆序的,所以num[0]是個位,num[1]是十位,num[2]是百位
    for(int i=0,up=0;i<n;i++)//算法參考小學加法,這里定義一個up進位標記
    {
        int temp=num1[i]+num2[i]+up;//up最開始設為0,因為在個位無法獲取進位
        num1[i]=temp%10;//若產生進位行為,則選取個位部分賦給num1
        up=temp/10;//在個位上,若個位相加產生進位,則用temp/10取整加到下一次的十位上
    }
    print_num(num1, n);
}
int main(){
    char buffer1[]="123456";//緩沖數組,將當前數組倒序寫入num1中
    char buffer2[]="78951234";//同上,寫入num2中
    int num1[N]={0};//將num1,2全部置為0,用來將緩沖數組寫入到num數組當中
    int num2[N]={0};
    int n=N;//定義上述兩個數組的長度為10
    for(int i=0,temp=(int)strlen(buffer1)-1;temp>=0;temp--)
        num1[i++]=buffer1[temp]-'0';//用倒序的方式將緩沖數組寫入num中,意味着num的第一位是個位,第二位是十位,三是百位...
    for(int i=0,temp=(int)strlen(buffer2)-1;temp>=0;temp--)
        num2[i++]=buffer2[temp]-'0';
    
    plus(num1, num2, n);//將兩數字相加
    printf("\n");
}

 

二.大數階乘

大數階乘的中心思想參考上述視頻和一篇博客,博客詳情:大數階乘運算

但是,這里需要說明一個點:

1*2=2,將2存到a[0]中,

接下來是用a[0]*3;

    2*3=6,將6儲存在a[0]中,

接下來是用a[0]*4;

    6*4=24,是兩位數,那么24%10==4存到a[0]中,24/10==2存到a[1]中,

接下來是用a[0]*5;a[1]*5+num(如果前一位相乘結果位數是兩位數,那么num就等於十位上的那個數字;如果是一位數,num==0)

    24*5=120,是三位數,那么120%10==0存到a[0]中,120/10%10==2存到a[1]中,120/100==1存到a[2]中

由於上述博客存在某些地方沒有說清楚的情況,這里解釋一下

關於上述博客的Q&A:

1.這里的num指的是什么?

答:這里的num指的是前面兩數值相乘后進位數位多少:例如6*4得24,這里的num值的是24/10=2,進位數為2,num=2

2.下面代碼為什么要充i=2開始?

答:如果這里看懂了代碼其實理解2不是很難,但是沒有看懂是真的難懂:

首先明確一點:5的階乘是1*2*3*4*5,我定義的value數組的第一位為1,而我的i是從2起的,這樣以來不就直接湊出了1*2了嗎?當我的i自增到3,我直接在value數組中找出1*2的值,拿他們去和3相乘,也就湊成了1*2*3了

3.如何在代碼當中表現出進位的思想?

答:我們以5!為例,當計算到1*2*3*4的時候,value當中的表現形式是42000000,從左到右依次是個位,十位,百位,千位...etc

(value表示的是24這個數字)

我們在關於j的循環當中拿i=5去和value數組求乘積:

5先和位於個位的4求積得20:20%10得0,0放入個位中;20/10得2,進位為2,up=2。(此時個位為0)

j++后,5再和value中的value[1]=2做乘積並且加上up進制:5*2+2=12,12%10=2放入十位,12%10=1放入up中(此時十位為2)

j++后,5再和value中百位value[2]=0做乘積同時加上up:5*0+1=1,1%10=1放入百位,1/10=0放入up中(此時百位為1)

j++,5再和千位做運算,運算結果為0,重復上述循環一直到關於i=5的j循環結束,開始下一輪。

4.若上述舉例子的不再是5而是20呢?最后幾項如何處理

答:假設1*2...19為止其結果==‘56’(純假設),

那么最后一項如何處理:56*20?

首先拿個位6和20相乘得120,120%10得0,0放到個位;120/10得12,up=12;(個位為0)

十位5和20相乘+up=112,112&10=2,2放到十位,112/10得11,up=11;(十位為2)

百位0與20相乘+up=11,11&10=1放到百位,11/10=1,up=1;(百位為1)

千位0與20相乘+up=1,1&10=1放到千位,1/10=0,up=0;(千位為1)

下面全都是0了,循環一直持續到value數組的末尾,方法同上一致。

最后value數組為0211000000

倒序之后就是1120,即56*20的結果就是1120。

 

#define n 13
int main(){
    int number=11;//定義要求階乘的數位number
    int value[n]={1};
//將存放number的階乘后結果的數組定義為value[]數組
//根據算法,階乘的第一項為1,因為階乘運算中最小的數字為1
    
    for(int up=0,i=2;i<=number;i++)//定義倆變量up和i,up負責進制,i是階乘當中的數字,i逐漸增大
        for(int j=0;j<n;j++)//我們是拿1*2*3*...,首先拿value[0]=1和2乘
        {
            int temp=value[j]*i+up;
            value[j]=temp%10;
            up=temp/10;
        }
    
    int i=n-1;//value是一個倒序的數組,第一位是個位,所以輸出是需要倒置的
    while(value[i]==0)
        --i;
    for(;i>=0;i--)
        printf("%d",value[i]);
    printf("\n");
}

三.大數乘法

兩個數值遠大於long long的表示范圍的數字相乘,用程序表示出來

這里我模擬正常運算的對位相乘思想,但是把最后一步相加進位的步驟單獨抽出來寫出來,用convert_normal函數表示

具體演示過程參考該視頻前幾分鍾的講解:高精度乘法

在傳統乘法中需要兩數值對位運算,例如357*384:

當位於個位上的4與7,5,3相乘的時候,其結果必須對應個位,十位,百位

當位於百位上的8與7,5,3相乘的時候,結果必須要對應十位,百位,千位

這也是為什么我要在multiply函數中引入k這個變量,k起到對位的作用。

這個算法當中,將最后一步(即3排數字的相加進位過程抽離出來,當讀寫成一個convert_normal函數)

在multiply函數中,result所得的結果直接將這三排數字對位相加,結果為28,76,73,39,9

接着在normal函數中這些數字全按照上面大數加法的思想轉化為正常數字

#include<string.h>
#define N 10
void transition(char buffer[],int num[])//把輸入的數組從char類型轉為int類型
{
    for(int i=(int)strlen(buffer)-1,j=0;i>=0;i--)
        num[j++]=buffer[i]-'0';
}
void bigdata_multiply(int num1[],int num2[],int after[])//大數乘法運算
{//函數模擬乘法的過程
    for(int i=0;i<N;i++)//num1
    {
        int k=i;
        for(int j=0;j<N;j++)//num2
            after[k++]+=num1[i]*num2[j];
    }
}
void print(int num[])
{
    int i=N-1;
    while(num[i]==0)
        --i;
    for(;i>=0;i--)
        printf("%d",num[i]);
}
void convert_normal(int number[])//轉換函數,將result數組中的數值轉化為正常數字
{
    for(int i=0,up=0;i<N;i++)
    {
        int temp=number[i]+up;
        number[i]=temp%10;
        up=temp/10;
    }
}
int main(){
    char buffer1[N];//定義一個過渡數組
    char buffer2[N];
    int result[N]={0};//定義計算結果的數組
    int num1[10]={0};//定義第一個數字
    int num2[10]={0};//定義第二個數字
    
    printf("num1=");
    scanf("%s",buffer1);
    printf("num2=");
    scanf("%s",buffer2);
    
    transition(buffer1, num1);//將num1,2數組逆置轉換為int數組
    transition(buffer2,num2);
    
    bigdata_multiply(num1,num2,result);
    convert_normal(result);
    print(result);
    printf("\n");
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM