1. 程式人生 > >大數四則運算的簡單演算法

大數四則運算的簡單演算法

大數相加

題目:任意兩個數相加,計算結果

還有種特殊情況  這個題目中的兩個數可能為正,可能為負

第一種情況,為正

思路:
1.將字串倒序並轉化為數字
2.逐位相加,並存入陣列s[i]
3.對陣列進行進位制換算(這裡有個需要特別注意的是 換算到最後,要考慮最後一位進位制k值是否為零)
4.將陣列反序輸出

所用程式碼如下

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define Max 100000
int main()
{
    char str1[Max+10],str2[Max+10];
    while( cin>>str1>>str2)
    {
        int a[Max+10]={0},b[Max+10]={0},s[Max*2+10]={0},len1,len2,len;
        len1=strlen(str1);
        len2=strlen(str2);
        len=len1>len2?len1:len2;
        int x=0;
        //將字串倒序並轉化為數字
        for(int i=len1-1;i>=0;i--)
            a[x++]=str1[i]-'0';
        x=0;
        for(int i=len2-1;i>=0;i--)
            b[x++]=str2[i]-'0';
        int k=0;
        //逐位相加,並存入陣列s[i]
       // 對陣列進行進位制換算
        for(int i=0;i<len;i++)
        {
            s[i]=(a[i]+b[i]+k)%10;
            k=(a[i]+b[i]+k)/10;
        }
        if(k!=0)
            printf("%d",k);
        int i;
        //將陣列反序輸出
        for(i=len-1;i>=0;i--)
        {
            if(s[i]!=0)
                break;
        }
        for(;i>=0;i--)
        {
            printf("%d",s[i]);
        }
        printf("\n");
    }
    return 0;
}

第二種情況   可能為負

思路

1.同上,先倒序輸出,並轉化為數字

2.判斷該數是否為負數,若為負,則對陣列內的每一個數字賦一個負號

3.逐位相加

4.判斷陣列s[i]的最後一位是否為負,分情況討論,若為負,則輸出一個負號

5.倒序輸出,並且對s[i]加絕對值

所需程式碼如下:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
char aa[10010],bb[10010];
int a[10010],b[10010],c[10010];
int lena,lenb,len;
int main()
{
    while(~scanf("%s%s",aa,bb))
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        int x=0;
        lena=strlen(aa),lenb=strlen(bb);
//反序輸出
        for(int i=lena-1; i>0; i--)
            a[x++]=aa[i]-'0';
//判斷是否為負
        if(aa[0]=='-')
        {
            lena--;
            for(int i=0; i<lena; i++)
                a[i]=-a[i];
        }
        else  a[lena-1]=aa[0]-'0';
        x=0;
        for(int i=lenb-1; i>0; i--)
            b[x++]=bb[i]-'0';
        if(bb[0]=='-')
        {
            lenb--;
            for(int i=0; i<lenb; i++)
                b[i]=-b[i];
        }
        else b[lenb-1]=bb[0]-'0';
        int k=0;
        len=lena>lenb?lena:lenb;
//逐位相加
        for(int i=0; i<len; i++)
        {
            c[i]=(a[i]+b[i]+k)%10;
            k=(a[i]+b[i]+k)/10;
        }
        if(k)
            c[len++]=k;
        while(len>1&&c[len-1]==0) len--;
        int flag=1;
//判斷是否為負數
        if(c[len-1]>=0)
        {
            for(int i=0; i<len; i++)
            {
                while(c[i]<0)
                {
                    c[i+1]--;
                    c[i]+=10;
                }
            }
        }
        if(c[len-1]<0)
        {
            flag=0;
            for(int i=0; i<len; i++)
            {
                while(c[i]>0)
                {
                    c[i+1]++;
                    c[i]-=10;
                }
            }
        }
        if(!flag) printf("-");
//倒序輸出,並且加上絕對值
        while(len>1&&c[len-1]==0) len--;
        for(int i=len-1; i>=0; i--)
            printf("%d",abs(c[i]));
        printf("\n");
    }
}

大數相乘

 

題目:  任意兩個數相乘,計算其結果

題目分析:該題主要注意結果的範圍,簡單的數字相乘,一般的程式碼程式可以運算,但大數的運算可能就會出現結果為負數,或者結果比所成積要小。所以要使用字串的形式來進行運算,儲存結果。

思路:

1.先將字串倒序並轉換為數字

2.逐位相乘,並存入一個數組s[i+j]中

3.處理進位,並消去多餘的0

4.轉換並把陣列s[i]反轉輸出

所用程式碼如下:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<iostream>
using namespace std;
#define Max 10000
int main()
{
    char str1[Max],str2[Max];
    int len1,len2;
    while(cin>>str1>>str2)
    {
    int a[Max+10]={0},b[Max+10]={0},s[2*Max+10]={0};
    len1=strlen(str1);
    len2=strlen(str2);
    int x=0;
    //將字串反轉過來,轉化為數字
    for(int i=len1-1;i>=0;i--)
    {
        a[x]=str1[i]-'0';
        x++;
    }
    x=0;
     for(int i=len2-1;i>=0;i--)
    {
        b[x]=str2[i]-'0';
        x++;
    }
    //對兩組字串中的數逐位相乘,存於s[i+j]
    for(int i=0;i<len1;i++)
    {
        for(int j=0;j<len2;j++)
        {
            s[i+j]+=(a[i]*b[j]);
        }
    }
    //得到的結果進行進位制處理
    for(int j=0;j<Max*2;j++)
    {
        if(s[j]>=10)
        {
            s[j+1]+=s[j]/10;
            s[j]%=10;
        }
    }
    int i;
     //除去多餘的0
  for(i=Max*2-1;i>=0;i--)
  {
      if(s[i]!=0)
        break;
  }
    //反轉陣列並輸出結果
    for(;i>=0;i--)
    {
        printf("%d",s[i]);
    }
    printf("\n");
    }
    return 0;
}


這是小編第一次編寫部落格,因為小編是剛學沒多久,裡面的程式碼也是比較淺顯易懂的,以後小編我會努力提升自我的水平的。。。。

 

大數減法

題目:任意兩個數相減,求其結果

思路:

1.

2.

3.

4.

#include<stdio.h>
#include<string.h>
#define MAX 1000//大數的最大位數

int main()
{
    int sum[MAX]= {0}; //存放計算的結果,低位在前,高位在後,即sum[0]是低位
    char a[]="987654321987654321";//第一個大數
    char b[]="123456789123456789";//第二個大數
    int i,j,len,blag;
    char *temp_a=a,*temp_b=b,*temp;
    int n2[MAX]= {0};
    int a1=strlen(a);//計算陣列num1的長度,即大數的位數
    int a2=strlen(b);//計算陣列num2的長度,即大數的位數

    //在進行減法之前要進行一些預處理
    blag=0;//為0表示結果是正整數,為1表示結果是負整數
    if(a1<a2)//如果被減數位數小於減數
    {
        blag=1;//標記結果為負數
        //交換兩個數,便於計算
        temp=temp_a;
        temp_a=temp_b;
        temp_b=temp;
        len=a1;
        a1=a2;
        a2=len;
    }
    else if(a1==a2)//如果被減數的位數等於減數的位數
    {
    //判斷哪個數大
        for(i=0; i<a1; i++)
        {
            if(a[i]==b[i])
                continue;
            if(a[i]>b[i])
            {
                blag=0;//標記結果為正數
                break;
            }
            else
            {
                blag=1;//標記結果為負數
                //交換兩個數,便於計算
                temp=temp_a;
                temp_a=temp_b;
                temp_b=temp;
                break;
            }
        }
    }
    len=a1>a2?a1:a2;//獲取較大的位數

    //將num1字元陣列的數字轉換為整型數且逆向儲存在整型陣列sum中,即低位在前,高位在後
    for(i=a1-1,j=0; i>=0; i--,j++)
        sum[j]=a[i]-48;

    //轉換第二個數
    for(i=a2-1,j=0; i>=0; i--,j++)
        n2[j]=b[i]-48;

    //將兩個大數相減
    for(i=0; i<=len; i++)
    {
        sum[i]=sum[i]-n2[i];//兩個數從低位開始相減
        if(sum[i]<0)//判斷是否有借位
        {
            //借位
            sum[i]+=10;
            sum[i+1]--;
        }
    }

    //計算結果長度
    for(i=a1-1; i>=0&&sum[i]==0; i--)
        len=i+1;
    if(blag==1)
    {
        sum[len]=-1;//在高位新增一個-1表示負數
        len++;
    }
    //輸出結果
    printf("%s\n-\n%s\n=\n",a,b);
    if(sum[i=len-1]<0)//根據高位是否是-1判斷是否是負數
    {
        printf("-");//輸出負號
        i--;
    }
    for(; i>=0; i--)
        printf("%d",sum[i]);
    printf("\n");
    return 0;
}

大數相除

大數除法是四則運算裡面最難的一種。不同於一般的模擬,除法操作不是模仿手工除法,而是利用減法操作來實現的。其基本思想是反覆做除法,看從被除數裡面最多能減去多少個除數,商就是多少。逐個減顯然太慢,要判斷一次最多能減少多少個整數(除數)的10的n次方。

以7546除以23為例:

    先用7546減去23的100倍,即減去2300,可以減3次,餘下646,此時商就是300 (300=100*3);

    然後646減去23的10倍,即減去230,可以減2次,餘下186,此時商就是320 (320=300+10*2);

    然後186減去23,可以減8次,餘下2,此時商就是328 (328=320+1*8);

    因為2除以23的結果小於1,而我們又不用計算小數點位,所以不必再繼續算下去了。

下面是C語言的兩個正大數相除的參考程式碼,計算結果中沒有小數:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
#define MAX 1000
/*
12   函式SubStract功能:
13   用長度為len1的大整數p1減去長度為len2的大整數p2
14   結果存在p1中,返回值代表結果的長度
15   不夠減:返回-1 , 正好夠:返回0
16 */
int SubStract(int *p1, int len1, int *p2, int len2)
{
    int i;
    if(len1 < len2)
        return -1;
    if(len1 == len2 )
    {
        // 判斷p1 > p2
        for(i = len1-1; i >= 0; i--)
        {
            if(p1[i] > p2[i])   // 若大,則滿足條件,可做減法
                break;
            else if(p1[i] < p2[i]) // 否則返回-1
                return -1;
        }
    }
    for(i = 0; i <= len1-1; i++)  // 從低位開始做減法
    {
        p1[i] -= p2[i];         // 相減
        if(p1[i] < 0)           // 若是否需要借位
        {
            // 借位
            p1[i] += 10;
            p1[i+1]--;
        }
    }
    for(i = len1-1; i >= 0; i--)  // 查詢結果的最高位
    {
        if( p1[i] )             //最高位第一個不為0
            return (i+1);       //得到位數並返回
    }
    return 0;                   //兩數相等的時候返回0
}


/*
 51   大數除法---結果不包括小數點
 52   num1 被除數
 53   num2 除數
 54   sum  商,存放計算的結果,即:num1/num2=sum
 55   返回陣列sum的有效長度,即商的位數
 56 */
int Division(char num1[], char num2[], char sum[])
{
    int k, i, j;
    int len1, len2, len=0;     //大數位數
    int dValue;                //兩大數相差位數
    int nTemp;                 //Subtract函式返回值
    int num_a[MAX] = {0};      //被除數
    int num_b[MAX] = {0};      //除數
    int num_c[MAX] = {0};      //商

    len1 = strlen(num1);       //獲得大數的位數
    len2 = strlen(num2);

    //將數字字元轉換成整型數,且翻轉儲存在整型陣列中
    for( j = 0, i = len1-1; i >= 0; j++, i-- )
        num_a[j] = num1[i] - '0';
    for( j = 0, i = len2-1; i >= 0; j++, i-- )
        num_b[j] = num2[i] - '0';

    if( len1 < len2 )          //如果被除數小於除數,直接返回-1,表示結果為0
    {
        return -1;
    }
    dValue = len1 - len2;      //相差位數
    for (i = len1-1; i >= 0; i--)    //將除數擴大,使得除數和被除數位數相等
    {
        if (i >= dValue)
            num_b[i] = num_b[i-dValue];
        else                         //低位置0
            num_b[i] = 0;
    }
    len2 = len1;
    for(j = 0; j <= dValue; j++ )    //重複呼叫,同時記錄減成功的次數,即為商
    {
        while((nTemp = SubStract(num_a, len1, num_b+j, len2-j)) >= 0)
        {
            len1 = nTemp;            //結果長度
            num_c[dValue-j]++;       //每成功減一次,將商的相應位加1
        }
    }
    // 計算商的位數,並將商放在sum字元陣列中
    for(i = MAX-1; num_c[i] == 0 && i >= 0; i-- );  //跳過高位0,獲取商的位數
    if(i >= 0)
        len = i + 1; // 儲存位數
    for(j = 0; i >= 0; i--, j++)     // 將結果複製到sum陣列中
        sum[j] = num_c[i] + '0';
    sum[j] = '\0';   // sum字元陣列結尾置0
    return len;      // 返回商的位數
}

int main()
{
    int i;
    int len;                // 商的位數
    char num1[MAX] = "1234567899876543210";   // 第一個大數
    char num2[MAX] = "20160415123025";              // 第二個大數
    char sum[MAX] = {0};    // 計算結果

    //scanf("%s", num1);      //以字串形式讀入大數
    //scanf("%s", num2);

    len = Division(num1, num2, sum);

    //輸出結果
    printf("%s\n  ÷\n%s\n  =\n", num1, num2);
    if( len>=0 )
    {
        for(i = 0; i < len; i++ )
            printf("%c", sum[i]);
    }
    else
    {
        printf("0");
    }
    printf("\n");

    return 0;
}