一.大数加法
定义两个足够大的数字,其数值远超过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(" "); }
二.大数阶乘
大数阶乘的中心思想参考上述视频和一篇博客,博客详情:大数阶乘运算
但是,这里需要说明一个点:
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(" "); }
三.大数乘法
两个数值远大于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(" "); }