高精除以高精
高精除以高精,求它们的商和余数。
算法分析
高精除以低精是对被除数的每一位都除以除数,(和高精加减乘不一样,高精的被除数不需要倒序存储在int数组中),而高精除以高精则是用减法模拟除法,对被除数的每一位都减去除数,一直减到当前位置的数字小于除数:
举个栗子
计算a/b,a是1234,b是56.正确结果应该是商22,余2.
采用一直减的过程用计算器截图如下:
数一下1234一共减去22次56剩下的数是2,2<56,因此商是22,余数是2.
参考代码1(一本通只能得33分,经过一个测试点)
#include<cstdio>
#include<cstring>
int a[350],b[350];
long long c;
int lena,lenb;
void init(int x[])
{
char aa[350];
scanf("%s",aa);
int len=strlen(aa);
for(int i=0;i<len;i++)
x[len-i]=aa[i]-'0';
x[0]=len;
}
int cmp(int a[],int b[])//a大于b就返回1,等于就返回0 小于就返回-1
{
if(a[0]>b[0]) return 1;
if(a[0]<b[0]) return -1;
for(int i=a[0];i>=1;i--)//两个数组长度一样,则依次比较到底哪个数组的值更大
{
if(a[i]>b[i]) return 1;
if(a[i]<b[i]) return -1;
}
return 0;//默认就是a和b是相等的
}
void gjj(int a[],int b[])
{
int flag;flag=cmp(a,b);
if(flag==0) {
a[0]=0;return;
}
if(flag==1){
for(int i=1;i<=a[0];i++)
{
if(a[i]<b[i])
{
a[i]+=10;
a[i+1]--;
}
a[i]=a[i]-b[i]; //得到新的a数组的值
}
while(a[a[0]]==0&&a[0]>0) a[0]--;
return;
}
}
void chugao(int a[],int b[])
{
while(cmp(a,b)>=0) {
c++;//记录除了多少次 ,但是如果这个次数精度也非常高,这样处理就是不行的。
gjj(a,b);
}
}
void print(int a[])
{
if(a[0]==0){
printf("0");return;
}
for(int i=a[0];i>0;i--)
printf("%d",a[i]);
printf("\n");
}
int main()
{
init(a);
init(b);
chugao(a,b);
printf("%lld\n",c);
print(a);//余数
return 0;
}
改进与思考
*上段代码中的c是用long long进行存储的,但是如果c的值使用任何数据范围都不能表示是,还是只能使用int数组c来表示这个商的值。
先看一本通书上的参考代码:
100分代码参考
#include<iostream>
#include<cstring>
using namespace std;
int a[500],b[500],c[500],d,i;
void init(int a[])
{string s;
cin>>s;//读入字符串
a[0]=s.length();//用a[0] 计算字符串s的位数
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';//将数串s转换成数组a,并倒序存储
}
void print(int a[])//打印输出
{int i;
if(a[0]==0) {cout<<0<<endl;return;//字符长度为0,输出0
}
for(i=a[0];i>=1;i--) cout<<a[i];//倒序输出
cout<<endl;
return;
}
int compare(int a[],int b[])//比较ab的大小关系,如果a大于b为1,a小于b为-1,a等于b为0
{int i;
if(a[0]>b[0]) return 1;
if(a[0]<b[0]) return -1;
for(i=a[0];i>0;i--) { //从高位到低位进行比较
if(a[i]>b[i]) return 1;
if(a[i]<b[i]) return -1;
}
return 0;
}
void jian(int a[],int b[]){//计算a=a-b
int flag,i;
flag=compare(a,b);//调用比较函数判断大小
if(flag==0) {
a[0]=0;return;
}
if(flag==1) {
for(i=1;i<=a[0];i++){
if(a[i]<b[i]){
a[i+1]--;
a[i]+=10;//不够减则向上借一位
}
a[i]-=b[i];
}
while(a[0]>0&&a[a[0]]==0) a[0]--;//修正a的位数
return;
}
}
void numcpy(int p[],int q[],int det)//复制p数组到q数组从det开始的地方
{
for(int i=1;i<=p[0];i++) q[i+det-1]=p[i];
q[0]=p[0]+det-1; }
void chugao(int a[],int b[],int c[])
{int i,tmp[101];
c[0]=a[0]-b[0]+1;
for(i=c[0];i>0;i--){
memset(tmp,0,sizeof(tmp));
numcpy(b,tmp,i);
while(compare(a,tmp)>=0){c[i]++;jian(a,tmp);
}
}
while(c[0]>0&&c[c[0]]==0) c[0]--;
return;
}
int main(){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
init(a);
init(b);
chugao(a,b,c);
print(c);
print(a);
return 0;
}
代码解释
栗子:1234-56,1234存在a数组,56存在b数组,将b数组存放在tmp数组中,但是并不是一对一的存放,而是第一次循环,让56存放成5600,比较a和tmp,显然1234<5600,下次又将56存放成560,1234-560=674,这时就能成功存放一个1在c中,而且是对应的c2中,然后发现674-560=114,c2更新为2。114-560<0,因此c2的更新到此结束,应该更新c1,将b56原样复制给tmp,114-56=58,c1=1;58-56=2,c1++更新为2,2-56<0。结束循环。
基于以上的计算,可以将22这个数字分别放在c2和c1中,tmp存在的意义在于不是像第一段代码中的计算到10次的时候循环加到22次,个人自行体会。
第一次写博客,mark一下。菜的不得了~