[算法]大数运算(加法、减法、阶乘、除数、幂运算)

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;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值