天天看點

模拟法計算大數加減乘除 (附帶例題)

模拟法計算大數加減乘除就是模拟列豎式的方法計算

大數加法

模拟豎式加法

首先是第一步先最低位對齊吧

例如:
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 類型的比較函數
           

字典序定義:

模拟法計算大數加減乘除 (附帶例題)

第二步就是最低位對齊

例如:
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;
}