高精度-基础

公用函数部分

//没什么,就是一个结构体
struct BigNum{
	int len;
	int d[10000];
}a,b;

//比较两个大数的大小,用于减法与除法中
//返回值为a1是否大于a2
bool cmp(BigNum a1,BigNum a2){
	if(a1.len!=a2.len) return a1.len>a2.len;
	for(int i = a1.len-1;i>=0;i--){
		if(a1.d[i]!=a2.d[i]) return a1.d[i]>a2.d[i];
	}
	return true;
}

//读入
void input(){
	string n1,n2;
	cin>>n1>>n2;
    
	int l1 = n1.length();
	int l2 = n2.length();
	
	for(int i = 0;i<l1;i++){
		a.d[l1-i-1] = n1[i] - '0';
	}
	a.len = l1;
	
	for(int i = 0;i<l2;i++){
		b.d[l2-i-1] = n2[i] - '0';
	}
	b.len = l2;
    //最高位下标为len-1
}

void output(){
	for(int i = a.len-1;i>=0;i--){
		cout<<a.d[i];
	}
}

高精度加法

void jia(){
	if(a.len<b.len) swap(a,b);
	for(int i = 0;i<a.len;i++){
		a.d[i] = a.d[i] + b.d[i];
	}
	for(int i = 0;i<a.len;i++){
		if(a.d[i]>=10){
			a.d[i] -= 10;
			a.d[i+1] += 1;
		}
	}
	if(a.d[a.len]!=0) a.d[a.len]++;
}

高精度减法

void jian(){
	bool zhengshu = cmp(a,b); 
	if(!zhengshu) swap(a,b);
    //大数减小数再加上负号
	
	for(int i = 0;i<a.len;i++){
		a.d[i] = a.d[i] - b.d[i];
	}
	for(int i = 0;i<a.len;i++){
		if(a.d[i]<0){
			a.d[i] += 10;
			a.d[i+1] -= 1;
		}
	}
	if(a.d[a.len-1]==0) a.d[a.len-1]--;
	if(!zhengshu) a.d[a.len-1] = -a.d[a.len-1];
}

高精度乘法

int mod(int a1,int n){
	while(a1>=n){
		a1 -= n;
	}
	return a1;
}

void cheng(){
    //按照人类习惯,大数在上,小数在下
    //拿小数各位去乘大数各位,结果存在 下标和 
    //即 第2位 乘 第3位 结果存在 第5位 内
    //位数最多增加 小数位数 个
    //位数最少增加 0 个
    /*
       9 9 9
   *     9 9
   ---------
     8 9 9 1
   8 9 9 1
   ---------
   9 8 9 0 1
    */
    
	BigNum t; 
	
    //大数在上,小数在下
	if(a.len<b.len) swap(a,b);
    //乘
	for(int i = 0;i<b.len;i++){
		for(int j = 0;j<a.len;j++){
            //因为两个大数都要重复使用所以需要另开辟一个BigNum t
            //各位相乘结果存在 下标和 内
			t.d[i+j] = t.d[i+j] + b.d[i] * a.d[j];
		}
	}
    //进位
	for(int i = 0;i<a.len+b.len;i++){
		if(t.d[i] >= 10){
			t.d[i+1] = t.d[i+1] + (t.d[i] - mod(t.d[i],10))/10;
			t.d[i] = mod(t.d[i],10);
		}
	}
    //判断位数增加数
	int jinwei = 0;
	for(int i = a.len;i<=a.len+b.len;i++){
		if(t.d[i]!=0) jinwei++;
	}
    //转移
	for(int i = 0;i<a.len+jinwei;i++){
		a.d[i] = t.d[i];
	}
    //改变位数
	a.len += jinwei;
}

高精度除法

我有一个很好的思路可惜这里写不下

真的会用到高精度除法吗

  • 大概思路
    1. 会用到高精度减法(用来取余数以及整除)
    2. 会用到高精度比较函数
    3. 从被除数首位开始除,不断在后面添加被除数下一位,直到被除数大于除数
    4. 商从最高位开始记录,需要倒序存在数组里
    5. 倒序输出

在大佬!LZB!的指导下弄明白了(大概)高精度除法

  1. 在除数后面补0(即逆序的右移操作)至位数相同

  2. 连续进行高精减法,用cnt来计数,减至a<b时,cnt即为“补0个数”位上的值

  3. 用第2步的结果(即上一步余数)做被除数,除数去掉一个0(即逆序左移一位)重复第2步

  4. 示例:

    假设计算 \(32517/54\)
    ①将除数 \(54\) 的位数补至小于被除数的最大数,即 \(54000\),所以千位为\(0\)
    ②高精减算出 \(32517/5400=6......117\),所以结果的百位为 \(6\)
    ③以 \(117\)为被除数,\(54\)不补 \(0\),即 \(117/54=2......9\)所以个位为 \(2\)
    所以整除结果为 \(602\),余数为 \(9\)

void youyiwei(BigNum &a,int n) {
	for(int i = a.len + n-1; i>=n; i--) {
		a.d[i] = a.d[i-n];
	}
	for(int i = 0; i<n; i++) {
		a.d[i] = 0;
	}
	a.len+=n;
}
void zuoyiwei(BigNum &a,int n) {
	for(int i = 0; i<a.len-n; i++) {
		a.d[i] = a.d[i+n];
	}
	for(int i = a.len-n; i<=a.len; i++) {
		a.d[i] = 0;
	}
	a.len-=n;
}
void chu() {
	BigNum r;
	if(!cmp(a,b)) {
		cout<<"0";
		return;
	}
	int xiangchaweishu = a.len-b.len;
	int s = xiangchaweishu;
	youyiwei(b,xiangchaweishu);
	
	while(xiangchaweishu>=0) {
		int cnt = 0;
		while(cmp(a,b)) {
			cnt++;
			jian();
		}
		r.d[xiangchaweishu] = cnt;
		zuoyiwei(b,1);
		xiangchaweishu -= 1;

	}
	for(int i = s;i>=0;i--){
		if(r.d[i]!=0){
			r.len = i+1;
			break;
		}
	}
	for(int i = r.len-1; i>=0; i--) {
		cout<<r.d[i];
	}
	cout<<endl;
}

另外,高精乘与高精除似乎在位数较大时会出现高位缺失、结果有误等问题(但是调不明白了TAT)
完整代码

posted @ 2021-11-26 19:37  Burnling  阅读(37)  评论(0编辑  收藏  举报