blog-ande

导航

高精度除法

第五部分 高精度除法

高精度除法的基本问题如下:

问题描述:
已知两个数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;
}

接下来就是比较难操作的高精度除以高精度了
我们知道,除法的本质是减法,多次的减法就是除法
所以高精度除以高精度的本质方法就是减法:
通过一次次的相减,得到最后的结果

但是——
我一个数除以另一个数的商太大怎么办?
这样会超时的啊,
所以减法就得精简起来
那么怎么精简呢?——高精除以低精的重要性就在这里了
在高精除以低精中,我们是一位位往下除,
那减法,是不是也一位位往下减就可以了

那么高精除以高精的整个步骤如下:

  1. 判断是否能够除
  2. 除到不能除
  3. 往上一位推

接下来我们来逐步剖析这三个部分:

第一部分就是判断能否除,
那这部分啊-其实很简单,只有一步,就是判断目前退位到的被除数是否比除数大(相等也行)
比较的程序就很简单了:
先判断位数,再从最高位开始比起,以此往下比,比到最后一位,如果相等,那么也可以作除法
代码如下:

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;
}

posted on 2023-07-14 00:03  HBGAnde  阅读(2620)  评论(0)    收藏  举报