一、大数的加法
我们都知道,两个数相加,就是从低位开始相加,满十进一即可。我们可以看出输入的两个加数是倒序存入数组的(存入789和678那么a[0]=7,a[1]=8,a[2]=9:b[0]=6,b[1]=7,b[2]=8),可以看出我们相加时要到着加(即从a[2]+b[2]开始)会很麻烦.并且如果最高位要进位不会有a[-1]来存,所以我们首先要将他们反过来存如数组,那么就可以从a[0]+b[0]开始
下面是将数组倒过来存的代码
void daoxu(char str[],int x[])
{
int i,j=strlen(str);
char s;
for(i=0;i<j;i++)
{
s=str[i]; //输入是字符串
x[j-i-1]=s-'0';//倒过来存入int型数组
}
}
那么接下来就是从低位开始加,满十进一
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int maxmax=1000;
const int N=2000000;
int y[N];
void daoxu(char str[],int x[])//将输入的大数倒序存入
{
int i,j=strlen(str);
char s;
for(i=0;i<j;i++)
{
s=str[i]; //输入是字符串
x[j-i-1]=s-'0'; //倒过来存入int型数组
}
} //存入结束
void qiu(int a[],int b[],int mun[])
{
int i;
for(i=0;i<maxmax;i++)
{
mun[i]=a[i]+b[i];
}
for(i=0;i<maxmax+1;i++)
{
mun[i+1]+=mun[i]/10;//每一位只能留一位数
mun[i]=mun[i]%10; //除了留的那一位其余都进位
}
}
int main()
{
char s1[maxmax],s2[maxmax];
int mun[maxmax*2];
int x1[maxmax];
int x2[maxmax];
memset(mun,0,sizeof(mun));//初始化数组
memset(x1,0,sizeof(x1)); //初始化数组
memset(x2,0,sizeof(x2)); //初始化数组
cin >> s1 >> s2;
daoxu(s1,x1); //倒序存入数组
daoxu(s2,x2); //倒序存入数组
qiu(x1,x2,mun); //求两大数相加
int j=maxmax*2-1,i;
while(mun[j]==0) //从最高位开始判断找出第一个非零位
j--;
for(i=j;i>=0;i--) //从高位倒着输出
{
printf("%d",mun[i]);
}
return 0;
}
二、大数的阶乘
首先看到阶乘大家都会做(一个for循环就可以),那么当这个阶乘结果非常大呢???超过了long long int了呢???
我们知道,乘法就是将被乘数的每一位与乘数相乘,满十进一,那我们不妨用这种思想来写。
#include <iostream>
using namespace std;
int main()
{
int n,m;
cin >> m; //输入m 代表m组测试数据
while(m--)
{
cin >> n;
int a[100001];
int i,j;
int count=1,next=0,mut; //mut乘积 next进位 count位数
a[0]=1;
for (i=2; i<=n; i++)
{
for (j=1; j<=count; j++)
{
mut=a[j-1]*i+next; //每位乘积等于该位当前乘积加进位数
a[j-1] = mut%10; //当前位只能保留一位数
next = mut/10; //下一位应加的进位数
}
while (next)//next>0 //所剩的应进位数不为0说明总位数不足
{
count++; //总位数加一 直至应进位数为零
a[count-1] = next%10;//同上“当前位只能保留一位数”
next = next/10;//同上 “下一位应加的进位数”
}
}
for (i=count-1; i>=0; i--)
cout << a[i]; //从高位到低位输出
cout << endl;
}
return 0;
}
具体可参考该链接: 大数阶乘问题
那么为了省时我们也可以不把被乘数分成一位一位的,代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n,i,j;
cin >> n;
int y[200000];
memset(y,0,sizeof(y));
int count=0,next=0,num; //mut乘积 next进位 count位数
y[0]=1;
for(i=2;i<=n;i++) //与一位一位乘一样
{
for(j=0;j<=count;j++)
{
num=y[j]*i+next;
y[j]=num%10000;
next=num/10000;
}
while(next)
{
y[++count]=next%10000;
next=next/10000;
}
} //结束
printf("%d",y[count]); //输出最高几位
for(i=count-1;i>=0;i--) //因为除最高位y[]都是四位的
printf("%04d",y[i]);//不足四位补0
return 0;
}
大数乘法
看完大数加法和大数阶乘,那么两个大数的乘法就不难理解了。就是先把乘数和被乘数从低位开始拆成一位一位的,并让乘数的每一位乘以被乘数的每一位,错位相加即可
下面我们来展示一道例题的代码
问题 F: 简单A*B
时间限制: 1 Sec 内存限制: 128 MB
题目描述
这是一个非常简单的题,计算A*B的值。
输入
第一行:数A
第二行:数B
数A,B是不超过1000位的正整数。
输出
A*B的值,答案独占一行。
样例输入
123456
234567
样例输出
28958703552
代码展示
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int maxmax=1000;
const int N=2000000;
int y[N];
void daoxu(char str[],int x[])//将输入的大数倒序存入
{
int i,j=strlen(str);
char s;
for(i=0;i<j;i++)
{
s=str[i]; //输入是字符串
x[j-i-1]=s-'0'; //倒过来存入int型数组
}
} //存入结束
void qiu(int a[],int b[],int mun[])
{
int i,j;
for(i=0;i<maxmax;i++)
{
for(j=0;j<maxmax;j++)
{
mun[i+j]+=a[i]*b[j];
//将乘数每一位乘以被乘数每一位
//num[i+j]是因为要错一位相加
}
}
for(i=0;i<maxmax*2-1;i++)
{
mun[i+1]+=mun[i]/10;//每一位只能留一位数
mun[i]=mun[i]%10; //除了留的那一位其余都进位
}
}
int main()
{
char s1[maxmax],s2[maxmax];
int mun[maxmax*2];
int x1[maxmax];
int x2[maxmax];
memset(mun,0,sizeof(mun));//初始化数组
memset(x1,0,sizeof(x1)); //初始化数组
memset(x2,0,sizeof(x2)); //初始化数组
cin >> s1 >> s2;
daoxu(s1,x1); //倒序存入数组
daoxu(s2,x2); //倒序存入数组
qiu(x1,x2,mun); //求两大数相乘
int j=maxmax*2-1,i;
while(mun[j]==0) //从最高位开始判断找出第一个非零位
j--;
for(i=j;i>=0;i--) //从高位倒着输出
{
printf("%d",mun[i]);
}
return 0;
}