模拟法计算大数加减乘除 (附带例题)

模拟法计算大数加减乘除就是模拟列竖式的方法计算

大数加法

模拟竖式加法
首先是第一步先最低位对齐吧

例如:
1 2 3 4 5 6 7 8 9
  2 0 0 0 1 1 2 8
我是这样子在实现的
strrev(a)//char的反转函数
reverse(a.begin(),a.end());//string的反转函数
反转过来就是这个
9 8 7 6 5 4 3 2 1
8 2 1 1 0 0 0 2 

第二步就是上下相加,满10进位

例如:
1 2 3 4 5 6 7 8 9
  2 0 0 0 1 1 2 8
-----------------
            1 1
1 4 3 4 5 7 9 1 7
因为我已经反转过来了,那就是这样的
9 8 7 6 5 4 3 2 1
8 2 1 1 0 0 0 2 
-----------------
  1 1
7 1 9 7 5 4 3 4 1
这样看起来很好加吧,一个for循环跑到天荒地老,(当然了,要是没得加就得退出了)
然后在反转一下就可以了
1 4 3 4 5 7 9 1 7

很简单吧,这样就计算出A+B了

例题

http://sustoj.com/JudgeOnline/problem.php?id=1952

AC code:
#include <stdio.h>//c 版
#include <string.h>
#define maxn 10000500
char ans[maxn];
char *strrev(char *str){
      char *p1, *p2;
      if (! str || ! *str){
            return str;
      }
      for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2){
            *p1 ^= *p2;
            *p2 ^= *p1;
            *p1 ^= *p2;
      }
      return str;
}
const char*num_plus(char *a,char *b){
  memset(ans,0,sizeof ans);
	int lena=strlen(a);
	int lenb=strlen(b);
	strrev(a);
	strrev(b);
	int yu=0;
  for(int i=0;;i++){
    if(i<lena&&i<lenb){
      ans[i]=(yu+a[i]-'0'+b[i]-'0')%10+'0';
      yu=(yu+a[i]-'0'+b[i]-'0')/10;
    }else if(i<lena){
      ans[i]=(yu+a[i]-'0')%10+'0';
      yu=(yu+a[i]-'0')/10;
    }else if(i<lenb){
      ans[i]=(yu+b[i]-'0')%10+'0';
      yu=(yu+b[i]-'0')/10;
    }else if(yu!=0){
      ans[i]=yu%10+'0';
      yu=yu/10;
    }else break;
  }
	strrev(ans);
	return ans;
}
char a[maxn],b[maxn];
int main(){
	while(~scanf("%s %s", a, b)){
    printf("%s\n", num_plus(a,b));
  }
  return 0;
}


#include <cstring>//c++ 版
#include <iostream>
#include <algorithm>
using namespace std;
string ans;
string num_push(string a,string b){
	ans.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());
  reverse(b.begin(),b.end());
  int yu=0;
  for(int i=0;;i++){
    if(i<lena&&i<lenb){
      ans+=(yu+a[i]-'0'+b[i]-'0')%10+'0';
      yu=(yu+a[i]-'0'+b[i]-'0')/10;
    }else if(i<lena){
      ans+=(yu+a[i]-'0')%10+'0';
      yu=(yu+a[i]-'0')/10;
    }else if(i<lenb){
      ans+=(yu+b[i]-'0')%10+'0';
      yu=(yu+b[i]-'0')/10;
    }else if(yu!=0){
      ans+=yu%10+'0';
      yu=yu/10;
    }else break;
  }
  reverse(ans.begin(),ans.end());
  return ans;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_push(a,b)<<endl;
  }
  return 0;
}


大数减法

模拟竖式减法
首先是第一步要判读大小吧(因为我只学过大减小的竖式计算)

因为没有前置零且都是正整数
所以谁位数多谁就大
要是位数一样的话,
那就是谁的那字典序大谁就大
用到了 strcmp(a,b)  //char 类型的比较函数

字典序定义:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019071623100764.pn
第二步就是最低位对齐

例如:
1 2 3 4 5 6 7 8 9
  2 0 0 0 1 1 2 8
我是这样子在实现的
strrev(a)//char的反转函数
reverse(a.begin(),a.end());//string的反转函数
反转过来就是这个
9 8 7 6 5 4 3 2 1
8 2 1 1 0 0 0 2 

第三步就是上下相减了,借位

例如:
1 2 3 4 5 6 7 8 9
  2 0 0 0 1 1 2 8
-----------------
1 0 3 4 5 5 6 6 1
因为我已经反转过来了,那就是这样的
9 8 7 6 5 4 3 2 1
8 2 1 1 0 0 0 2 
-----------------
1 6 6 5 5 4 3 0 1
这样看起来很好减吧,一个for循环跑到天荒地老,(当然了,要是没得减就得退出了)
然后在反转一下就可以了
1 0 3 4 5 5 6 6 1

借位

1 0 0 0 0
  9 9 9 9
----------
0 0 0 0 1
我是这样实现借位的,先反转过来
0 0 0 0 1
9 9 9 9
----------
因为0减不过9
所以要向后借位
所以第一位借到10后就变成了1
第二位是'0'的话就继续向后借,
反正上面的肯定大于下面的,所以肯定能借到的
借到就减一就行了
就是这个样子了

0 0 0 0 1
9 9 9 9
----------
1 0 0 0 0
翻转过来就是
0 0 0 0 1 了
当然不能要前置0,所以我在反转前就把前置零去掉,不要忘了要是小减大就要添上'-'
例题:

http://sustoj.com/JudgeOnline/problem.php?id=1948

AC code:
#include <stdio.h> //c 版
#include <string.h>
#define maxn 100000
char ans[maxn];
char* strrev(char* s)
{
    /* h指向s的头部 */
    char* h = s;
    char* t = s;
    char ch;
    /* t指向s的尾部 */
    while(*t++){};
    t--;    /* 与t++抵消 */
    t--;    /* 回跳过结束符'\0' */
    /* 当h和t未重合时,交换它们所指向的字符 */
    while(h < t)
    {
        ch = *h;
        *h++ = *t;    /* h向尾部移动 */
        *t-- = ch;    /* t向头部移动 */
    }
    return(s);
}
int judge(char *a, char *b){
  int lena=strlen(a);
  int lenb=strlen(b);
  if(lena>lenb) return 1;
  if(lena<lenb) return -1;
  return strcmp(a,b);
}
const char *num_sub(char *a, char *b){
  char aa[maxn],bb[maxn];
  memset(aa,0,sizeof aa);
  memset(bb,0,sizeof bb);
  memset(ans,0,sizeof ans);
  char *as=ans;
  int cnt=judge(a,b);
  bool bo=false;
  if(cnt>0){
    strcpy(aa,a);
    strcpy(bb,b);
    bo=false;
  }else if(cnt<0){
    strcpy(aa,b);
    strcpy(bb,a);
    bo=true;
  }else{
    ans[0]='0';
    return as;
  }
  int lena=strlen(aa);
  int lenb=strlen(bb);
  strrev(aa);
  strrev(bb);
  int i;
  for(i=0;;i++){
    if(i<lena&&i<lenb){
      if(aa[i]>=bb[i]){
        ans[i]=aa[i]-bb[i]+'0';
      }else {
        ans[i]=aa[i]-bb[i]+10+'0';
        for(int j=i+1;;j++){
          if(aa[j]=='0') aa[j]='9';
          else{
            aa[j]--;
            break;
          }
        }
      }
    }else if(i<lena){
      ans[i]=aa[i];
    }else if(i<lenb){
      ans[i]=bb[i];
    }else break;
  }
  while(i--){
    ans[i+1]='\0';
    if(ans[i]-'0'>0){
      break;
    }
  }
  if(bo) ans[i+1]='-';
  strrev(ans);
  return as;
}
char a[maxn],b[maxn];
int main(){
  while(~scanf("%s %s", a, b)){
    printf("%s\n", num_sub(a,b));
  }
  return 0;
}

#include <bits/stdc++.h> //c++ 版
using namespace std;
#define maxn 100000
string ans;
int judge(string a,string b){
  int lena=a.size();
  int lenb=b.size();
  if(lena>lenb) return 1;
  if(lena<lenb) return -1;
  if(a>b) return 1;
  if(a==b) return 0;
  if(a<b) return -1;
}
string num_mul(string a,string b){
  string aa,bb;
  aa.clear();
  bb.clear();
  ans.clear();
  bool bo;
  int cnt=judge(a,b);
  if(cnt>0){
    aa=a;
    bb=b;
    bo=false;
  }else if(cnt<0){
    aa=b;
    bb=a;
    bo=true;
  }else if(cnt==0){
    ans+='0';
    return ans;
  }
  reverse(aa.begin(),aa.end());
  reverse(bb.begin(),bb.end());
  int lena=aa.size();
  int lenb=bb.size();
  int i;
  for(i=0;;i++){
    if(i<lena&&i<lenb){
      if(aa[i]>=bb[i]){
        ans+=aa[i]-bb[i]+'0';
      }else{
        ans+=aa[i]-bb[i]+10+'0';
        for(int j=i+1;;j++){
          if(aa[j]=='0') aa[j]='9';
          else {
            aa[j]--;
            break;
          }
        }
      }
    }else if(i<lena){
      ans+=aa[i];
    }else if(i<lenb){
      ans+=bb[i];
    }else break;
  }
  while(i--){
    if(ans[i]-'0'>0){
      break;
    }
  }
  ans.erase(i+1,lena-i);
  if(bo) ans+='-';
  reverse(ans.begin(),ans.end());
  return ans;
}
string a,b;
int main(){
  while(cin>>a>>b){
      cout<<num_mul(a,b)<<endl;
  }
  return 0;
}

大数乘法

第一步还是要最低位对齐

例如:
1 2 3 4 5 6 7 8 9
  2 0 0 0 1 1 2 8
我是这样子在实现的
strrev(a)//char的反转函数
reverse(a.begin(),a.end());//string的反转函数
反转过来就是这个
9 8 7 6 5 4 3 2 1
8 2 1 1 0 0 0 2 

第二步就是上下相乘,向后进位

 9  8  7  6  5  4  3  2  1
 8  2  1  1  0  0  0  2
------------------
72 64 56 48 40 32 24 16  8---------8*(987654321)
   18 16 14 12 10  8  6  4  2 ---------2*(987654321)
       9  8  7  6  5  4  3  2  1---------1*(987654321)
          9  8  7  6  5  4  3  2  1---------1*(987654321)
             0  0  0  0  0  0  0  0  0---------0*(987654321)
                0  0  0  0  0  0  0  0  0---------0*(987654321)
                   0  0  0  0  0  0  0  0  0---------0*(987654321)
                     18 16 14 12 10  8  6  4  2 ---------2*(987654321)
-------------------------------------------------------------------------
72 82 81 79 67 55 43 49 35 21 15 11  8  6  4  2 
-------------------------------------------------------------------------
    7  8  8  8  7  6  4  5  4  2  1  1 
 2  9  9  7  5  2  9  3  0  5  7  2  9  6  4  2 
 反转过来就是这样了
 2469275039257992
例题

http://sustoj.com/JudgeOnline/problem.php?id=1985

AC code:
#include <stdio.h>//c 版
#include <string.h>
using namespace std;
#define maxn 500000
int ans[maxn];
char num[maxn];
char *strrev(char *str)
{
      char *p1, *p2;
      if (! str || ! *str)
      {
            return str;
      }
      for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
      {
            *p1 ^= *p2;
            *p2 ^= *p1;
            *p1 ^= *p2;
      }
      return str;
}
char* num_mul(char *a, char *b){
  memset(ans,0,sizeof ans);
  memset(num,0,sizeof num);
  char *as=num;
  int nu=0;
  memset(ans,0,sizeof ans);
  int lena=strlen(a);
  int lenb=strlen(b);
  strrev(a);
  strrev(b);
  for(int i=0;i<lena;i++){
    for(int j=0;j<lenb;j++){
        ans[i+j]+=(a[i]-'0')*(b[j]-'0');
    }
  }
  int i;
  int yu=0;
  int len=lena+lenb-1;
  for(i=0;;i++){
    if(i<len||yu!=0){
      yu=ans[i]+yu;
      ans[i]=yu%10;
      yu=yu/10;
    }else break;
  }
  while(i--){
    num[nu++]=ans[i]+'0';
  }
  return num;
}
char a[maxn],b[maxn];
int main(){
  while(~scanf("%s %s", a, b)){
    if(strcmp(a,"0")==0) printf("0\n");
    else if(strcmp(b,"0")==0) printf("0\n");
    else printf("%s\n", num_mul(a,b));
  }
  return 0;
}

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100000
int ans[maxn];
string num;
string num_mul(string a,string b){
  memset(ans,0,sizeof ans);
  num.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());
  reverse(b.begin(),b.end());
  for(int i=0;i<lena;i++){
    for(int j=0;j<lenb;j++){
      ans[i+j]+=(a[i]-'0')*(b[j]-'0');
    }
  }
  int yu=0;
  int i;
  int len=lena+lenb-1;
  for(i=0;;i++){
    if(i<len||yu!=0){
      yu=ans[i]+yu;
      ans[i]=yu%10;
      yu=yu/10;
    }else break;
  }
  while(i--){
    num+=ans[i]+'0';
  }
  return num;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_mul(a,b)<<endl;
  }
  return 0;
}


大数除法

已经学会大数减法了,那就不用再去模拟大数除法了
可以一直减下去用大数减了多少步,但这样会有缺陷,比如说
10000000000 1 \frac{10000000000}{1} 110000000000 那就要跑10000000000次,这样肯定会超时的
那可以换一种方法
比如说 a b \frac{a}{b} ba
先给分母 b b b末尾补零直到与 a a a长度相同,得到 b ′ b^{'} b
比较 a a a b ′ b^{'} b的大小,大的话一直减,减到 a a a小于 b ′ b^{'} b,然后再给 b ′ b^{'} b去掉末尾的零
一直循环上面布置,直到 b ′ b^{'} b还原到b的时候停止
这样可能会出现前置零,那就去掉前置零就好了
比如
10000000000 1 \frac{10000000000}{1} 110000000000 那就跑11次就好了

例题

http://sustoj.com/JudgeOnline/problem.php?id=1986

AC code :
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000
char anss[maxn];
char ans[maxn];
char *strrev(char *str)
{
      char *p1, *p2;
      if (! str || ! *str)
      {
            return str;
      }
      for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
      {
            *p1 ^= *p2;
            *p2 ^= *p1;
            *p1 ^= *p2;
      }
      return str;
}
int judge(char *a, char *b){
  int lena=strlen(a);
  int lenb=strlen(b);
  if(lena>lenb) return 1;
  if(lena<lenb) return -1;
  return strcmp(a,b);
}
const char *num_sub(char *a, char *b){
  char aa[maxn],bb[maxn];
  memset(aa,0,sizeof aa);
  memset(bb,0,sizeof bb);
  memset(ans,0,sizeof ans);
  char *as=ans;
  int cnt=judge(a,b);
  bool bo=false;
  if(cnt>0){
    strcpy(aa,a);
    strcpy(bb,b);
    bo=false;
  }else if(cnt<0){
    strcpy(aa,b);
    strcpy(bb,a);
    bo=true;
  }else{
    ans[0]='0';
    return as;
  }
  int lena=strlen(aa);
  int lenb=strlen(bb);
  strrev(aa);
  strrev(bb);
  int i;
  for(i=0;;i++){
    if(i<lena&&i<lenb){
      if(aa[i]>=bb[i]){
        ans[i]=aa[i]-bb[i]+'0';
      }else {
        ans[i]=aa[i]-bb[i]+10+'0';
        for(int j=i+1;;j++){
          if(aa[j]=='0') aa[j]='9';
          else{
            aa[j]--;
            break;
          }
        }
      }
    }else if(i<lena){
      ans[i]=aa[i];
    }else if(i<lenb){
      ans[i]=bb[i];
    }else break;
  }
  while(i--){
    ans[i+1]='\0';
    if(ans[i]-'0'>0){
      break;
    }
  }
  if(bo) ans[i+1]='-';
  strrev(ans);
  return as;
}
char *num_div(char *a, char *b){
  memset(anss,0,sizeof anss);
  int nu=0;
  int lena=strlen(a);
  int lenb=strlen(b);
  for(int i=lenb;i<lena;i++){
    b[i]='0';
  }
  while(lena-->=lenb){
    int i=0;
    while(judge(a,b)>=0){
      i++;
      strcpy(a,num_sub(a,b));
    }
    anss[nu++]=i+'0';
    b[lena]='\0';
  }
  if(anss[0]=='\0'){
    anss[0]='0';
    return anss;
  }
  if(anss[0]=='0')
  return anss+1;
  return anss;
}
char a[maxn],b[maxn];
int main(){
  while(~scanf("%s %s", a, b)){
    printf("%s\n", num_div(a,b));
    cout<<a<<endl;
  }
}
#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
string ans;
string anss;
string yu;
int judge(string a,string b){
  int lena=a.size();
  int lenb=b.size();
  if(lena>lenb) return 1;
  if(lena<lenb) return -1;
  if(a>b) return 1;
  if(a==b) return 0;
  if(a<b) return -1;
}
string num_mul(string a,string b){
  string aa,bb;
  aa.clear();
  bb.clear();
  ans.clear();
  bool bo;
  int cnt=judge(a,b);
  if(cnt>0){
    aa=a;
    bb=b;
    bo=false;
  }else if(cnt<0){
    aa=b;
    bb=a;
    bo=true;
  }else if(cnt==0){
    ans+='0';
    return ans;
  }
  reverse(aa.begin(),aa.end());
  reverse(bb.begin(),bb.end());
  int lena=aa.size();
  int lenb=bb.size();
  int i;
  for(i=0;;i++){
    if(i<lena&&i<lenb){
      if(aa[i]>=bb[i]){
        ans+=aa[i]-bb[i]+'0';
      }else{
        ans+=aa[i]-bb[i]+10+'0';
        for(int j=i+1;;j++){
          if(aa[j]=='0') aa[j]='9';
          else {
            aa[j]--;
            break;
          }
        }
      }
    }else if(i<lena){
      ans+=aa[i];
    }else if(i<lenb){
      ans+=bb[i];
    }else break;
  }
  while(i--){
    if(ans[i]-'0'>0){
      break;
    }
  }
  ans.erase(i+1,lena-i);
  if(bo) ans+='-';
  reverse(ans.begin(),ans.end());
  return ans;
}
string num_div(string a,string b){
	anss.clear();
	int lena=a.size();
	int lenb=b.size();
	for(int i=lenb;i<lena;i++){
		b+='0';
	}
	while(lena-->=lenb){
		int i=0;
		while(judge(a,b)>=0){
			a=num_mul(a,b);
			i++;
		}
		anss+=(i+'0');
		b.erase(lena);
	}
	yu=a;
	if(anss.size()==0){
		anss+='0';
		return anss;
	}
	if(anss[0]=='0')
		anss.erase(0,1);
  return anss;
}
string a,b;
int main(){
  while(cin>>a>>b){
      cout<<num_div(a,b)<<endl;
			cout<<yu<<endl;
  }
  return 0;
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值