高精度除法
第五部分 高精度除法
高精度除法的基本问题如下:
问题描述:
已知两个数a,b,求两个数的商数据输入:
700 35
数据输出:20数据范围: \(1\leq b,a\leq 10^{1000}\)
高精度除法是四种高精度中比较好理解,但不好写的算法,高精度除法总共有两种形式:
高精/低精;高精/高精
高精除以低精的难度比较简单,可以运用简单的除法进行。除法的方法相信大家很熟悉了,这里我们用表格呈现除法:
| 数组 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| a[] | 0 | 0 | 7 | 0 | 0 |
| b | 35 | ||||
| c[] | 0 | 0 | 0 | 0 | 0 |
| 余数 | 0 |
那么我们首先就是除法,在没讲高精度除以高精度前,现在就可以直接进行除法运算
倒序取出第一个数,将7加入余数中,用余数相除,除完之后发现有余数,接着就把余数加入当中,将这一位求得的商加入其中
| 数组 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| a[] | 0 | 0 | 7 | 0 | 0 |
| b | 35 | ||||
| c[] | 0 | 0 | 0 | 0 | 0 |
| 余数 | 7 |
接着是下一步,此时将余数进行保留之后,乘10,并加入下一位数,同样地用余数进行除法运算,此时的结果得到了这样子:
| 数组 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| a[] | 0 | 0 | 7 | 0 | 0 |
| b | 35 | ||||
| c[] | 0 | 2 | 0 | 0 | 0 |
| 余数 | 0 |
接着重复计算,就可以得到最后的结果了。
高精除以低精的除法的步骤就是一步一步相除,得到结果,没有任何的技巧,除法的核心代码如下(因为上文的存储是倒序的,所以这里也只能够写倒序的了,在写的时候可以正序写(不过得保证输入输出正序)):
int c[100], cn=0, y=0; //y存储余数
for (int i=an-1; i>0; i--){
y=y*10+a[i];
c[i]=y/b;
y=y%b;
}
接着我们把其余的部分加入,最后的程序是这样的:
#include <iostream>
#include <stdlib.h>
#include <sstream>
using namespace std;
int main(void){
string a,b; //a, b表示两个加数
int bl;
int al[10000]={0};
cin>>a>>b;
//输入段
stringstream ss;
ss<<b;
ss>>bl;
//这一段代码是将b数组直接从字符串转为整数
int an=a.length(), bn=b.length();
for (int i=0; i<an; i++){
al[i]=a[an-i-1]-'0';
}
//存储段
int c[10000]={0}, cn=an, y=0; //y存储余数
for (int i=an-1; i>=0; i--){
y=y*10+al[i];
c[i]=y/bl;
y=y%bl;
}//除法段
while (c[cn-1]==0&&cn!=1) cn--;
for (int i=0; i<cn; i++){
cout<<c[cn-i-1];
}//输出段
cout<<endl;
cout<<y;
//这里下方的输出是输出余数
return 0;
}
接下来就是比较难操作的高精度除以高精度了
我们知道,除法的本质是减法,多次的减法就是除法
所以高精度除以高精度的本质方法就是减法:
通过一次次的相减,得到最后的结果
但是——
我一个数除以另一个数的商太大怎么办?
这样会超时的啊,
所以减法就得精简起来
那么怎么精简呢?——高精除以低精的重要性就在这里了
在高精除以低精中,我们是一位位往下除,
那减法,是不是也一位位往下减就可以了
那么高精除以高精的整个步骤如下:
- 判断是否能够除
- 除到不能除
- 往上一位推
接下来我们来逐步剖析这三个部分:
第一部分就是判断能否除,
那这部分啊-其实很简单,只有一步,就是判断目前退位到的被除数是否比除数大(相等也行)
比较的程序就很简单了:
先判断位数,再从最高位开始比起,以此往下比,比到最后一位,如果相等,那么也可以作除法
代码如下:
int compare(int p){
if (al[p+bn]>0) return 1; //这里判断的方法就是判断a[]中b总共位数的下一位是否有得除
else{
for (int i=bn-1; i>=0; i--){
if (al[p+i]>bl[i]){
return 1;
}else if (al[p+i]<bl[i]){
return 0;
}
}
}
return 1;
}
第二部分和第三部分本质上就是除法
高精除以低精的除法的程序我们按部就班,把中间的除法变成减法的程序然后再加上判断是否能除,然后余数的部分省略就好了:
代码如下:
for (int i=an-1; i>=0; i--){
while (compare(i)){ //用while循环判断是否能够除
c[i]++; //将c数组的值相加,存下减了几次(这个用不是人话来说就是商)
for (int j=0; j<bn; j++){
a[i+j]=a[i+j]-b[j];
}for (int j=0; j<bn; j++){
if (a[i+j]<0){
a[i+j+1]--;
a[i+j]+=10;
}
}
}
}
剩下就是这几天打了很多遍的高精度输入-存储-输出代码,调整位数的代码需要使用减法优化。
接下来是完整代码:
#include <iostream>
#include <stdlib.h>
using namespace std;
string a, b; //a, b表示两个被减数与减数
int al[100]={0}, bl[100]={0};
int an, bn;
int compare(int p){
if (al[p+bn]>0) return 1; //这里判断的方法就是判断a[]中b总共位数的下一位是否有得除
else{
for (int i=bn-1; i>=0; i--){
if (al[p+i]>bl[i]){
return 1;
}else if (al[p+i]<bl[i]){
return 0;
}
}
}
return 1;
}
int main(void){
cin>>a>>b;
an=a.length(), bn=b.length(); //获取a, b的长度
//输入段
for (int i=0; i<an; i++){
al[i]=a[an-i-1]-'0';
}for (int i=0; i<bn; i++){
bl[i]=b[bn-i-1]-'0';
}
//存储段
int c[1000]={0}, cn=an;
for (int i=an-1; i>=0; i--){
while (compare(i)){ //用while循环判断是否能够除
c[i]++; //将c数组的值相加,存下减了几次(这个用不是人话来说就是商)
for (int j=0; j<bn; j++){
al[i+j]=al[i+j]-bl[j];
}for (int j=0; j<bn; j++){
if (al[i+j]<0){
al[i+j+1]--;
al[i+j]+=10;
}
}
}
}
//进位段
while (c[cn-1]==0&&cn!=1){
cn--;
}//调整段
for (int i=0; i<cn; i++){
cout<<c[cn-i-1];
}//输出段
return 0;
}
浙公网安备 33010602011771号