[算法]大數運算(加法、減法、階乘、除數、冪運算)

1.大數加法:

在這裏插入圖片描述
注意加法需要判斷最高位的下一位!!!
☞ C語言實現:
這種方法定義了太多數組,它的實現核心與階乘相似。

#include<stdio.h>
#include<iostream>
using namespace std;
int main(){

   int arr[1010];
   int brr[1010];
   int crr[2000];
   string sa,sb;
   cin>>sa>>sb;
   for(int i=0;i<sa.size();i++)///注意這裏下表是反過來算的
    arr[i]=sa[sa.size()-i-1]-48;
    for(int i=0;i<sb.size();i++)
    brr[i]=sb[sb.size()-i-1]-48;
    int lenc = max(sa.size(),sb.size());
    int num=0;
    for(int i=0;i<lenc;i++){
        int temp=arr[i]+brr[i]+num;
        crr[i]=temp%10;
        num=temp/10;
    }
    if(num)///最高位的下一位如果不爲0,肯定爲1
      crr[lenc]=1;
    if(num) for(int i=lenc;i>=0;i--) cout<<crr[i];
    else for(int i=lenc-1;i>=0;i--) cout<<crr[i];
}

☞ C語言實現改進版:

#include<stdio.h>
#include<iostream>
using namespace std;
int main(){

   int arr[10010];
   int brr[10010];
   string sa,sb;
   cin>>sa>>sb;
   for(int i=0;i<sa.size();i++)///注意這裏下表是反過來算的
    arr[i]=sa[sa.size()-i-1]-48;///也可以sa[sa.size()-i-1]-'0'
    for(int i=0;i<sb.size();i++)
    brr[i]=sb[sb.size()-i-1]-48;
    int lenc = max(sa.size(),sb.size());

    for(int i=0;i<lenc;i++) arr[i]=arr[i]+brr[i];///對應的每一位先全部加到a數組

    for(int i=0;i<lenc;i++){
        arr[i+1]=arr[i+1]+arr[i]/10;
        arr[i]=arr[i]%10;
    }
    if(arr[lenc]) for(int i=lenc;i>=0;i--) cout<<arr[i];
    else for(int i=lenc-1;i>=0;i--) cout<<arr[i];
}

☞ Java語言實現:

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		BigInteger a = sc.nextBigInteger();
		BigInteger b = sc.nextBigInteger();
		BigInteger c = a.add(b);
		System.out.println(c);
	}
}

雖然Java中有BigInteger對象可以定義超大數據,但是我們一般能不調用就不調用,爲了提高程序效率。

import java.util.*;

public class Main {
   public static void main(String [] args) {
      Scanner sc = new Scanner(System.in);
      String stra = sc.next();
      String strb = sc.next();
      int len=Math.max(stra.length(),strb.length());
      int arr[] = new int[len+1];
      int brr[] = new int[len];

      for(int i=0;i<stra.length();i++)
         arr[i]=Integer.valueOf(stra.charAt(stra.length()-1-i)-48);
      for(int i=0;i<strb.length();i++)
         brr[i]=Integer.valueOf(strb.charAt(strb.length()-1-i)-48);

      for(int i=0;i<len;i++) arr[i]=arr[i]+brr[i];

         for(int i=0;i<len;i++) {
         arr[i+1]=arr[i+1]+arr[i]/10;
         arr[i]=arr[i]%10;
      }
      if(arr[len]!=0) for(int i=len;i>=0;i--) System.out.print(arr[i]);
      else for(int i=len-1;i>=0;i--) System.out.print(arr[i]);
   }
}

2.大數減法

減法分兩種情況:分清楚被減數和減數大小的先後和不分被減數和減數的大小先後
以不分被減數和減數的大小先後爲例,由於大數用字符表示,所以我們可以從位數和大小考慮:

  • 兩數位數不同:位數大的數減去位數小的數
  • 兩數位數相同,但大小不同:從最高位開始比較,一位一位地比。

注意問題: 防止輸出會有0的情況,因爲得到的最終數可能比兩數中都要小。

#include<stdio.h>
#include<iostream>
using namespace std;
int main(){

   int arr[10010];
   int brr[10010];
   string sa,sb;
   cin>>sa>>sb;
   int lena = sa.size();
   int lenb = sb.size();
   for(int i=0;i<lena;i++)///注意這裏下標是反過來算的
    arr[i]=sa[lena-i-1]-48;

    for(int i=0;i<lenb;i++)
    brr[i]=sb[lenb-i-1]-48;

    bool flag=false;
    if(lena<lenb) flag = true;///判斷兩數大小
    else if(lena==lenb){
       for(int i=lena-1;i>=0;i--){
        if(arr[i]<brr[i]) flag =true;///從後面返回遍歷,在兩數相同位的情況下,如果arr當前位小於brr當前位,說明arr數小於b數
       }
     }///其他情況爲false
    int sum[10010]={0};
    int j;
    if(flag){
       for(j=0;j<lenb;j++)
         sum[j] = brr[j]-arr[j];///先全部位對應減去
        for(j=0;j<lenb;j++)
         if(sum[j]<0&&j+1<lenb){
           sum[j]+=10;
           sum[j+1]--;
         }
    }else {
       for(j=0;j<lena;j++)
         sum[j] = arr[j]-brr[j];
        for(j=0;j<lena;j++)
         if(sum[j]<0&&j+1<lena){
           sum[j]+=10;
           sum[j+1]--;
         }
    }
    int k=j-1;
    while(sum[k]==0) k--;///去掉最高位出現0的情況

    for(int i=k;i>=0;i--) cout<<sum[i];
}

3. 大數階乘:

在這裏插入圖片描述

import java.util.*;

public class Main {
   public static void main(String [] args) {
      Scanner sc = new Scanner(System.in);
      int n = sc.nextInt();
      int maxx=4000;
      int []arr = new int[maxx];
      arr[0]=1;
      int temp;
      for(int i=2;i<=n;i++){
         int num=0;
         for(int j=0;j<maxx;j++){
            temp = arr[j]*i+num;
            arr[j] = temp%10;///儲存當前位的數
            num = temp/10;
         }
      }
      int k;
          for(k=maxx-1;k>=0;k--) if(arr[k]!=0)  break;
          
          for(int j=k;j>=0;j--) System.out.print(arr[j]);
   }
}

3.大數除法

大數除法分爲兩種情況:

  • 從輸入情況:一是高精度除以低精度(大數除小數),一是高精度除以高精度(大數除以大數)
  • 從輸出情況:一是求商(取模),一是求餘(取餘)。
    基本思想是反覆做除法,看從被除數裏面最多能減去多少個除數,商就是多少(下面的數組crr)。把除數增大到與被除數一樣的位數(除數小於被除數,除數加0),如130/5,商的位數必定爲兩數位數差(針對於大數除以大數),除數增大到500,130/500,除數大於被除數,除數要減小,130/50,商的十位加1…
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int arr[1010];          //被除數
int brr[1010];          //除數
int crr[1010];          //商
char stra[1010];      //讀入的第一個大數
char strb[1010];      //讀入的第二個大數
int jianfa( int *x, int *y, int lena, int lenb )
{
    int i;
    if( lena < lenb )
        return -1;
    if( lena == lenb )
    {
        for( i=lena-1; i>=0; i-- )
        {
            if( x[i] > y[i] )
                break;
            else if( x[i] < y[i] )
                return -1;
        }
    }
    for( i=0; i<lena; i++ )  //從低位開始做減法
    {
        x[i] =x[i]-y[i];
        if( x[i] < 0 )          //若x[i]<0,則需要借位
        {
            x[i] += 10;         //借1當10
            x[i+1]--;           //高位減1
        }
    }
    for( i=lena-1; i>=0; i-- )       //查找結果的最高位
        if( x[i] )                  //最高位第一個不爲0
            return (i+1);       //得到位數並返回
    return 0;                  //兩數相等的時候返回0
}
int main()
{
    int n, k, i, j;             //n:測試數據組數
    int lena, lenb;             //大數位數
    scanf("%s %s", stra,strb);        //以字符串形式讀入大數
        lena = strlen(stra);  //獲得大數的位數
        lenb = strlen(strb);
    int len,temp;
        for( j=0, i=lena-1; i>=0; j++, i-- )
            arr[j] = stra[i] - '0';  //將字符串轉換成對應的整數,顛倒存儲
        for( j=0, i=lenb-1; i>=0; j++, i-- )
            brr[j] = strb[i] - '0';

        if( lena < lenb ) {//如果被除數小於除數,結果爲0
             printf("商:0\n");
             printf("餘:%s",stra);
             puts("");
             return;
        }


        len = lena - lenb;    //相差位數
        for ( i=lena-1; i>=0; i-- )    //將除數擴大,使得除數和被除數位數相等
        {
            if ( i>=len )
                brr[i] = brr[i-len];
            else                     //低位置0
                brr[i] = 0;
        }
        lenb = lena;
        for( j=0; j<=len; j++ )      //不斷減數,記錄減成功的次數,即爲商
        {
            while((temp = jianfa(arr,brr+j,lena,lenb-j)) >= 0)///
            {
                lena = temp;      //更新被除數位數
                crr[len-j]++;//每成功減一次,將商的相應位加1
            }
        }

        k=len-1;
        while(crr[k]==0) k--;
        printf("商:");
        if(k>=0){
              for(i=k; i>=0; i-- ) printf("%d", crr[i]);
        }
        else printf("0");
        int ka = lena-1;
        while(crr[ka]==0) ka--;
         printf("\n餘:");
         if(ka>=0){
              for(i=ka; i>=0; i-- ) printf("%d", crr[i]);
        }
        else printf("0");
    return 0;
}

下面的方法只能用於高精度除以低精度

4.大數的冪運算

此法跟乘法一樣,只不過相乘的是自身。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100///按題目需求
int num[MAX];
char str[MAX];
int arr[MAX*MAX];
void chengfa(int num[],int arr[],int len){
   int s[MAX*MAX]={0};
   for(int i=0;i<len;i++)
         for(int j=0;j<MAX*MAX;j++)///由於自乘可能超出原數字串的長度
             s[i+j]=s[i+j]+num[i]*arr[j];///每一位各自相乘

   for(int i=0;i<MAX*MAX;i++){
         if(s[i]>=10) s[i+1]=s[i+1]+s[i]/10;
         arr[i]=s[i]%10;
   }

}
int main(){
    int n;
    scanf("%s %d",str,&n);
    int len = strlen(str);
    int a=0,b=0;
    for(int i=len-1;i>=0;i--)
    {
        num[a++]=str[i]-'0';
        arr[b++]=str[i]-'0';
    }///注意這裏與上面不同,要各自定義下標
    n--;
    while(n){///不斷自乘,直到冪數爲0
       chengfa(num,arr,len);
       n--;
    }
    int k=MAX*MAX-1;
    while(arr[k]==0) k--;
    printf("%d\n",k);
    for(int i=k;i>=0;i--) printf("%d",arr[i]);
    printf("\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章