c语言之大数基本运算

c语言--大数的基本运算

今天我想给大家介绍有关大数运算的方法,大数这里可以算是一个难点同样也是重点,以下的代码只针对非负数,大家在看之前可以自己思考一下。

大数加法

考虑到整型变量的范围有限,所以我们用字符数组来定义输入的两个大数,首先要使它们相应的位对齐,位数少的在前补0,然后各个位数的相加要考虑到进位,这里我定义为s。下面是全部代码:

#include"stdio.h"
#include"string.h"
int main()
{
    int i,m,len,len1;
    char a[100000],b[100000];
    scanf("%s",a);
    scanf("%s",b);
    len=strlen(a);
    len1=strlen(b);
	m=(len>len1)?len:len1;
    for(i=0;i<50;i++)  
    a[50-1-i]=a[len-1-i];//使其右对齐
	for(i=0;i<50-len;i++)
	a[i]='0';//前面补0
	for(i=0;i<50;i++) 
	b[50-1-i]=b[len1-1-i];//使其右对齐
	for(i=0;i<50-len1;i++)
	b[i]='0';//前面补0
	for(i=0;i<50;i++) 
	c[i]='0';//初始化0
	s=0;//进位
	for(i=0;i<m;i++) 
	{
		c[50-1-i]=((a[50-1-i]-'0')+(b[50-1-i]-'0')+s)%10+'0';
		s=((a[50-1-i]-'0')+(b[50-1-i]-'0')+s)/10;
	} 
	c[50-1-m]=s+'0';
	printf("%s",c);
}

这里需要注意的是:大数用的是字符存储,不能直接相加,要先将其转化成数字再进行运算。
emmm,我这里没有去掉前导0。

大数阶乘

阶乘和加法的原理一样都是相应的位进行运算然后要考虑到进位,这里我声明了一个自定义函数来计算阶乘,切记不要忽略了特殊情况。

#include"stdio.h" 
#include"string.h"
void print_factorial(int n)//阶乘的函数
{
	if(n<0)
	{
		printf("error\n");
		return;
	}
	else if(n==0)
	{
		printf("%d\n",1);
		return;
	}
	int a[100000]={1},i,j;
	int t=0,len=1,tem;//t为进位,len为位数 
	for(i=2;i<=n;i++) 
	{
		t=0;
		for(j=0;j<len;j++)
		{
			tem=a[j]*i;//乘积的值
	    	a[j]=(tem+t)%10;//每一位分离出来
			t=(tem+t)/10;
			if(t!=0&&j==len-1)//判断位数是否增加
			len++;
		}
	}
	for(i=len-1;i>=0;i--) 
	{
		printf("%d",a[i]);//输出结果 
	}
}
int main()
{
	int n;
	scanf("%d",&n);//输入几的阶乘
	print_factorial(n); 
}

这里需要注意的是:a数组是逆着存最后的结果的,所以输出时需要逆序输出。

大数高阶幂

这里我来举两个特殊的例子:计算3的100次方和浮点数的幂,其实高阶幂的算法和阶乘一样,只是部分地方需要改动,你只要理解了最核心的代码就问题不大。以下是3的100次方的代码:

#include"stdio.h" 
#include"string.h"
int main()
{
	int a[1000]={1},i,j,t,tem,len=1;
	char b[1000],c[1000];
	gets(b);
	for(i=1;i<=100;i++)//计算3^100 
	{
		t=0;
		for(j=0;j<len;j++)
		{
			tem=a[j]*3;
			a[j]=(tem+t)%10;//每一位分离出来 
			t=(tem+t)/10;//t为进位 
			if(t!=0&&j==len-1)
			len++;
 		} 
		
	}//逆着存的 
	j=0; 
	for(i=len-1;i>=0;i--)
	printf("%d",a[i]);//输出结果
	printf("\n");
}

同样注意的是,这里也是逆序输出哦~

我们再来看一下浮点数的高阶幂,它比整数要复杂的多,我们来看一下这种题的要求:

本题中需要注意的点:
1.先找到小数点的位置,纪录并去掉。
2.去掉无意义的0。
3.纪录小数点后有效位的位数。
4.每次计算中都要去除无意义的0。
5.计算最后结果中小数点的位置。
6.将小数点加入到计算结果中。
7.去掉最终结果中的无意义的0并输出。

例如:
输入:
95.123 12
输出:548815620517731830194541.899025343415715973535967221869852721
完整代码如下:

#include"stdio.h" 
#include"string.h"
int len=1; 
void multiply(int a[],int n,int num)
{
	int i,j,t1,tem;//t1为进位
	for(i=1;i<=n;i++) 
	{
		t1=0;
		for(j=0;j<len;j++) 
		{
			tem=a[j]*num;
			a[j]=(tem+t1)%10;
			t1=(tem+t1)/10;
			if(t1!=0&&j==len-1)
			len++;
		}
	}//逆着存的 
}
int main()
{
	char R[10];
	int n,num,t,i,j,l;//t为小数点的位数 
	while(scanf("%s%d",R,&n)!=EOF)
	{
		int a[150]={1};
		num=0,t=0;
		for(i=0;i<strlen(R);i++)
		{
			if(R[i]=='.')
			{
				t=(strlen(R)-1-i)*n;
			}
			else
			{
				num=num*10+R[i]-48;
			}
		}
		multiply(a,n,num);
		if(len<=t)//数组a的位数小于小数位数 
		{
			printf(".");
			for(i=0;i<t-len;i++)
			printf("0");
			for(i=len-1;i>=0;i--)
			printf("%d",a[i]);
		}
		else
		{
			j=0;
			while(a[j]==0&&j<t)//去掉末尾没用的零 
			{
				j++;
			}
			l=len;
			for(i=len-1;i>=j;i--)//去掉前导0 
			{
				if(a[i]==0)
				l--;
				if(a[i]!=0)
				break;
			}
			for(i=l-1;i>=j;i--)
			{
				if(i+1==t)
				printf(".");
				printf("%d",a[i]);
			}
		}
		printf("\n");
	} 
}

上面这个题比较复杂,要考虑的问题比较多,所以代码写起来比较繁琐,希望大家不会的可以好好琢磨一下,试着自己敲出来。

大数乘法

 

这是我认为这里面最难的一种运算,它是阶乘和加法的结合,首先我们要搞清楚多位数与多位数相乘的原理和过程并从中发现规律。
其核心就是:两个大数,从末尾开始逐位相乘。相乘结果保存在另外一个数组里面(也从数组末尾开始依次往前保存)。然后将保存位置大于9的数进行进位处理。
为了便于理解举个例子:

我们通过举例可以发现相乘后的位数k不会超过m+n;这样我们在写代码时就便利不少。
以下是完整代码:

#include<stdio.h>  
#include<math.h>  
#include<string.h>  
#define M 10005  
char s1[M],s2[M],s[M];  
int a[M],b[M],c[M];  
int main()  
{  
    int i,j,m,n,k;  
    while(~scanf("%s%s",s1,s2))  
    {  
        memset(c,0,sizeof(c));  
        n=strlen(s1);  
        m=strlen(s2);  
        k=n+m;//保证相乘后的位数不会大于k  
        printf("s1的长度=%d s2的长度=%d\n",n,m);  
       //把字符串s1s2逆序用数字排列  
        for(i=0; i<n; i++)  
            a[i]=s1[n-i-1]-'0';  
        for(i=0; i<m; i++)  
            b[i]=s2[m-1-i]-'0';  
          //乘运算
        for(i=0; i<n; i++)  
            for(j=0; j<m; j++)  
                c[i+j]+=a[i]*b[j];  
        for(i=0; i<k; i++)  
        {  
            if(c[i]>=10)  
            {  
                c[i+1]+=c[i]/10;  
                c[i]%=10;  
            }  
        }  
     //去除前导0 
        i=k;  
        while(c[i]==0) i--;  
     //判断两个非负数之积是否为0,以及逆序打印c[]  
        if(i<0) printf("0");  
        else  
        {  
            for(; i>=0; i--)  
                printf("%d",c[i]);  
        }  
        printf("\n");  
    }  
    return 0;  
}  

先介绍这几种大数的基本算法,还有大数减法和大数除法我没有提,大家可以下去好好想想,掌握了这些你在大数方面的算法题就没啥大问题。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值