[C++]高精度算法

目录

高精度加法    高精度减法    高精度乘法    高精度除法    附录


高精度加法

用程序来模拟竖式加法即可,注意在输出的时候除去多余的前导零。

程序代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX_SIZE = 3333;
inline void High_precision_Addition(int *a, int *b, int *c) {
	c[0] = 1; int x = 0;
	while (c[0] <= a[0] || c[0] <= b[0]) {
		c[c[0]] = a[c[0]] + b[c[0]] + x;
		x = c[c[0]] / 10;
		c[c[0]] %= 10;
		++c[0];	
	};
	c[c[0]] = x;
	while (c[c[0]] == 0 && c[0] > 1) --c[0];	
};
int main(int argc, char *argv[]) {
	char str1[MAX_SIZE], str2[MAX_SIZE];
	cin >> str1 >> str2;
	int a[MAX_SIZE], b[MAX_SIZE], c[MAX_SIZE];
	memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(c, 0, sizeof c);
	a[0] = strlen(str1); b[0] = strlen(str2);
	for (int i = 0; i < a[0]; ++i) a[a[0] - i] = str1[i] - '0'; 
	for (int i = 0; i < b[0]; ++i) b[b[0] - i] = str2[i] - '0';
	High_precision_Addition(a, b, c);
	for (int i = c[0]; i >= 1; --i) printf("%d", c[i]); cout.put('\n'); //和
	return 0;	
};

高精度减法

用程序来模拟竖式减法即可,与高精度加法类似,不过得考虑被减数与减数的大小关系还得考虑借位,所以代码相对于高精度加法更为复杂。

程序代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX_SIZE = 3333;
inline bool Is_swap(char *__x_, char *__y_) {
	char Mid_Element[MAX_SIZE];
	if ((strlen(__x_) < strlen(__y_)) || (strlen(__x_) == strlen(__y_) && strcmp(__x_, __y_) < 0)) {
		strcpy(Mid_Element, __x_);
		strcpy(__x_, __y_);
		strcpy(__y_, Mid_Element);
		return true;
	};	
	return false;
};
inline void High_precision_Subtraction(int *a, int *b, int *c) {
	 c[0] = 1;
	while (c[0] <= a[0] || c[0] <= b[0]) {
		if (a[c[0]] < b[c[0]]) {
			a[c[0]] += 10;
			--a[c[0] + 1];	
		};
		c[c[0]]	= a[c[0]] - b[c[0]];
		++c[0];
	};
	while (c[c[0]] == 0 && c[0] > 1) --c[0];
};
int main(int argc, char *argv[]) {
	char str1[MAX_SIZE], str2[MAX_SIZE];
	cin >> str1 >> str2; bool flag = Is_swap(str1, str2);
	int a[MAX_SIZE], b[MAX_SIZE], c[MAX_SIZE];
	memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(c, 0, sizeof c);
	a[0] = strlen(str1); b[0] = strlen(str2);
	for (int i = 0; i < a[0]; ++i) a[a[0] - i] = str1[i] - '0'; 
	for (int i = 0; i < b[0]; ++i) b[b[0] - i] = str2[i] - '0';
	High_precision_Subtraction(a, b, c);
	if (flag == true) cout.put('-');
	for (int i = c[0]; i >= 1; --i) printf("%d", c[i]); cout.put('\n'); //差
	return 0;	
};

高精度乘法

用程序模拟竖式乘法即可,在做乘法运算时,同样也有进位,同时对每一位进行乘法运算时,必须进行错位相加。

程序代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX_SIZE = 3333;
inline void High_precision_Multiplication(int *a, int *b, int *c) {
	int x;
	for (int i = 1; i <= a[0]; ++i) {
		x = 0;
		for (int j = 1; j <= b[0]; ++j) {
			c[i + j - 1] = a[i] * b[j] + x + c[i + j - 1];
			x = c[i + j - 1] / 10;
			c[i + j - 1] %= 10;	
		};
		c[i + b[0]] = x;	
	};
	c[0] = a[0] + b[0];
	while (c[c[0]] == 0 && c[0] > 1) --c[0];
};
int main(int argc, char *argv[]) {
	char str1[MAX_SIZE], str2[MAX_SIZE];
	cin >> str1 >> str2;
	int a[MAX_SIZE], b[MAX_SIZE], c[MAX_SIZE];
	memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(c, 0, sizeof c);
	a[0] = strlen(str1); b[0] = strlen(str2); 
	for (int i = 0; i < a[0]; ++i) a[a[0] - i] = str1[i] - '0'; 
	for (int i = 0; i < b[0]; ++i) b[b[0] - i] = str2[i] - '0';
	High_precision_Multiplication(a, b, c);
	for (int i = c[0]; i >= 1; --i) cout << c[i]; cout.put('\n'); //积
	return 0;
};

高精度除法

高精度除法一般有高精度除以低精度与高精度除以高精度,前者代码较为简单,后者则作用范围更加广阔。高精度除以低精度与前三种高精度算法类似,都是按位运算;而高精度除以高精度则是以减法来模拟除法。

程序代码1

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX_SIZE = 3333;
inline int High_precision_Division(int *a, int b, int *c) {
	int x = 0;
	for (int i = 1; i <= a[0]; ++i) {
		c[i] = (x * 10 + a[i]) / b;
		x = (x * 10 + a[i]) % b;	
	};
	c[0] = 1;
	while (c[c[0]] == 0 && c[0] < a[0]) ++c[0];
    return x;
};
int main(int argc, char *argv[]) {
	char str[MAX_SIZE]; int b; 
	cin >> str >> b;
	int a[MAX_SIZE], c[MAX_SIZE];
	memset(a, 0, sizeof a); memset(c, 0, sizeof c);
	a[0] = strlen(str); 
	for (int i = 0; i < a[0]; ++i) a[i + 1] = str[i] - '0'; 
	int x = High_precision_Division(a, b, c);
	for (int i = c[0]; i <= a[0]; ++i) cout << c[i]; cout.put('\n'); //商
	cout << x << endl; //余数
	return 0;	
};

程序代码2

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
const int MAX_SIZE = 3333;
inline void Input(int *radix) {
	string str; cin >> str; radix[0] = str.length();
	for (int i = 0; i < radix[0]; ++i) radix[radix[0] - i] = str[i] - '0';	
};
inline void Print(const int *radix) {
    if (radix[0] == 0) {cout << 0 << endl; return;};
	for (int i = radix[0]; i >= 1; --i) printf("%d", radix[i]);
	cout.put('\n'); return;	   	   	
};
inline int Compare(const int *__x_, const int *__y_) {
	if (__x_[0] > __y_[0]) return 1;
	if (__x_[0] < __y_[0]) return -1;
	for (int i = __x_[0]; i >= 1; --i) {
		if (__x_[i] == __y_[i]) continue;
		else if (__x_[i] > __y_[i]) return 1;
		else if (__x_[i] < __y_[i]) return -1;	
	};
	return 0;   	
};
inline void Subtraction(int *__x_, int *__y_) {
	int sign = Compare(__x_, __y_);
	if (sign == 0) {__x_[0] = 0; return;}; 
	if (sign == 1) {	
		for (int i = 1; i <= __x_[0]; ++i) {
			if (__x_[i] < __y_[i]) {
				__x_[i] += 10; --__x_[i + 1];	
			};
			__x_[i] -= __y_[i];	
		};
		while (__x_[__x_[0]] == 0 && __x_[0] > 0) --__x_[0]; return; 	
	};
};
inline void Numcpy(const int *radix, int *pending, int pos) {
	for (int i = 1; i <= radix[0]; ++i) pending[i + pos - 1] = radix[i];
	pending[0] = radix[0] + pos - 1; 
};
inline void High_precision_Division(int *a, int *b, int *c) {
	int sign = Compare(a, b);
	if (sign == -1) {c[0] = 1; c[1] = 0; return;}; 
	if (sign == 1 || sign == 0) { 
		int Temp[MAX_SIZE]; c[0] = a[0] - b[0] + 1;
		for (int i = c[0]; i >= 1; --i) {
			memset(Temp, 0, sizeof Temp); Numcpy(b, Temp, i);
			while (Compare(a, Temp) != -1) {++c[i]; Subtraction(a, Temp);};	
		};
		while (c[c[0]] == 0 && c[0] > 0) --c[0]; return;	
	};
};
int main(int argc, char *argv[]) {
	int a[MAX_SIZE], b[MAX_SIZE], c[MAX_SIZE];
	memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(c, 0, sizeof c);
	Input(a); Input(b); High_precision_Division(a, b, c);
	Print(c); Print(a); //商与余数
	return 0;
};	 

附录

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
using namespace std;
struct BigInt { //输入只能为正整数,减法计算可以输出负数
	const static int MAX_SIZE = 1111; int data[MAX_SIZE]; char sign; //结构体中的量
	static void value_swap(BigInt& x, BigInt& y) {
		BigInt t; t = x; x = y; y = t;
	}
	static int compare(const int* x, const int* y) { //用于判断两个大数的大小,1为左边大,-1为右边大,0为一样大
		if (x[0] > y[0]) return 1; if (x[0] < y[0]) return -1;
		for (int i = x[0]; i >= 1; i--) { if (x[i] > y[i]) return 1; if (x[i] < y[i]) return -1; }
		return 0;
	}
	static void numcpy(const int* x, int* y, const int pos) { //将x数组中的元素从pos开始复制到y元素中
		y[0] = x[0] + pos - 1;
		for (int i = 1; i <= x[0]; i++) y[i + pos - 1] = x[i];
	}
	static void subtraction(int* x, int* y) { //大数x减去大数y并将结果保存到x中
		int sign = compare(x, y);
		if (sign == 0) { x[0] = 1; x[1] = 0;  return; }; //若两数相同则直接返回,两数一小一大不作处理
		if (sign == 1) {
			for (int i = 1; i <= x[0]; i++) {
				if (x[i] < y[i]) { x[i] += 10; x[i + 1]--; } //借位
				x[i] -= y[i];
			}
			while (x[x[0]] == 0 && x[0] > 0) x[0]--; //去除前导零
		}
	}
	BigInt() { //构造BigInt
		memset(data, 0, sizeof(data)); data[0] = 1; sign = '+'; //初始化
	}
	friend istream& operator >> (istream& is, BigInt& r) { //cin输入
		string str; is >> str; r.data[0] = str.length(); //将键盘输入暂存到str中,data[0]代表BigInt长度
		for (int i = 0; i < r.data[0]; ++i) r.data[r.data[0] - i] = str[i] - '0'; //数组中倒序存储,如str="123",那么data[1]=3,data[2]=2,data[3]=1
		return is; //返回输入流
	}
	friend ostream& operator << (ostream& os, BigInt r) { //cout输出
		if (r.sign == '-') cout.put(r.sign); //判断结果是否为负数(减法)
		for (int i = r.data[0]; i >= 1; --i) cout << r.data[i]; //倒序输出
		return os; //返回输出流
	}
	BigInt operator + (const BigInt& r) const { //高精度加法
		BigInt t; t.data[0] = 1; int x = 0; //t为暂存量,r为'+'右边的数,this指针指向'+'左边的数;x表示进位的量
		while (t.data[0] <= r.data[0] || t.data[0] <= this->data[0]) { //t的长度小于等于两个加数的任意一个即可
			t.data[t.data[0]] = r.data[t.data[0]] + this->data[t.data[0]] + x; //模拟竖式加法,从最后一位(即数组的第一位)开始
			x = t.data[t.data[0]] / 10; //进位
			t.data[t.data[0]] %= 10; //进位后取模
			t.data[0]++; //处理下一位
		}
		t.data[t.data[0]] = x; //处理两个三位数进成四位数的情况
		while (t.data[t.data[0]] == 0 && t.data[0] > 1) t.data[0]--; //去掉前导零
		return t;
	}
	BigInt operator - (const BigInt& r) const {
		BigInt t; t.data[0] = 1; BigInt i = *this, j = r; //一会儿可能会交换'-'左右两端的值,为了防止源数据受影响,故利用临时变量i, j(被减数与减数)
		if (i.data[0] < j.data[0]) { value_swap(i, j);  t.sign = '-'; } //如果i长度不如j,则一定为负数,故交换
		else if (i.data[0] == j.data[0]) { //i和j长度相同的情况
			int len = i.data[0];
			while (len > 0 && i.data[len] == j.data[len]) len--; //从后往前,直到出现两数大小不同的两位
			if (len > 0 && i.data[len] < j.data[len]) { value_swap(i, j); t.sign = '-'; } //如233 - 333, 233百位小于333百位, 故交换; len大于0是要排除两数相同的情况
		}
		while (t.data[0] <= i.data[0] || t.data[0] <= j.data[0]) { //t的长度小于减数或被减数即可
			if (i.data[t.data[0]] < j.data[t.data[0]]) { //模拟竖式减法,判断是否需要借位(因为已然判断了两数的大小关系,所以不会存在不够借的情况)
				i.data[t.data[0]] += 10;
				i.data[t.data[0] + 1]--;
			}
			t.data[t.data[0]] = i.data[t.data[0]] - j.data[t.data[0]];
			t.data[0]++;
		}
		while (t.data[t.data[0]] == 0 && t.data[0] > 1) t.data[0]--; //去除前导零
		return t;
	}
	BigInt operator * (const BigInt& r) const {
		BigInt t; t.data[0] = 1; int x = 0;
		for (int i = 1; i <= this->data[0]; i++) { //数据均为逆序处理;模拟竖式乘法,但是乘加顺序与日常相反(比如:111*13=13+130+1300而不是=333+1110)
			x = 0; //进位初始化
			for (int j = 1; j <= r.data[0]; j++) {
				t.data[i + j - 1] = this->data[i] * r.data[j] + x + t.data[i + j - 1]; //i+j-1用于处理错位相加的情况
				x = t.data[i + j - 1] / 10; //进位
				t.data[i + j - 1] %= 10; //进位后剩下的量
			}
			t.data[i + r.data[0]] = x; //最高位
		}
		t.data[0] = this->data[0] + r.data[0]; //t的长度最长为两个乘数长度之和
		while (t.data[t.data[0]] == 0 && t.data[0] > 0) t.data[0]--; //去掉前导零
		return t;
	}
	BigInt operator / (const int& r) const {
		BigInt t; t.data[0] = this->data[0]; int x = 0; //依旧是朴实无华的初始化,不过此处x为余数
		for (int i = this->data[0]; i >= 1; i--) { //顺序模拟竖式运算,但是要先假设商的长度和被除数一样,没什么好说的
			t.data[i] = (x * 10 + this->data[i]) / r;
			x = (x * 10 + this->data[i]) % r;
		}
		while (t.data[t.data[0]] == 0 && t.data[0] > 1) t.data[0]--; //去掉前导零
		return t;
	}
	BigInt operator / (const BigInt& r) const { //高精度除以高精度!
		BigInt t; int sign = compare(this->data, r.data); //先进行两个大数的初步判断,一小一大或者一样大直接返回节约时间,一大一小才用处理(见上面的compare函数)
		if (sign == -1) { t.data[0] = 1; t.data[1] = 0; return t; }
		else if (sign == 0) { t.data[0] = 1; t.data[1] = 1; return t; }
		else {
			BigInt temp, p = *this; t.data[0] = p.data[0] - r.data[0] + 1; //商的长度为被除数长度减除数长度加一(归纳法可得);为了不改变*this的大小,用p来代替运算
			for (int i = t.data[0]; i >= 1; i--) { //利用减法实现除法,顺序模拟
				memset(temp.data, 0, sizeof temp.data); //temp为中间量,每次使用时需要初始化
				numcpy(r.data, temp.data, i); //将除数数据从第i位开始一一放入temp中
				while (compare(p.data, temp.data) != -1) { t.data[i]++; subtraction(p.data, temp.data); } //如果被除数大小大于temp大小则减去n个temp直到不能再减并使该位不断t.data[i]++
			} //例如:p[]=4 4321, temp=3 006, 运算后的p[]=3 436, t.data[3]++
			while (t.data[t.data[0]] == 0 && t.data[0] > 1) t.data[0]--; //去除前导零
			return t;
		}
	}
	int operator % (const int& r) const {
		int x = 0;
		for (int i = this->data[0]; i >= 1; i--) x = (x * 10 + this->data[i]) % r; //正序读入,模拟竖式除法
		return x;
	}
	BigInt operator % (const BigInt& r) const { //高精度模即为高精度除法取余数,稍加修改即可
		BigInt t, p = *this; int sign = compare(p.data, r.data);
		if (sign == -1) return p; //若被除数比除数小,则余数等于被除数,直接返回即可
		else if (sign == 0) { p.data[0] = 1; p.data[1] = 0; return p; } //被除数等于除数余数为零
		else {
			BigInt temp; t.data[0] = p.data[0] - r.data[0] + 1; 
			for (int i = t.data[0]; i >= 1; i--) {
				memset(temp.data, 0, sizeof temp.data);
				numcpy(r.data, temp.data, i);
				while (compare(p.data, temp.data) != -1) { t.data[i]++; subtraction(p.data, temp.data); }
			}
			while (t.data[t.data[0]] == 0 && t.data[0] > 1) t.data[0]--;
			return p;
		}
	}
};
int main(void) {
	BigInt a, b;
	cin >> a >> b;
	cout << a + b << endl;
	cout << a - b << endl;
	cout << a * b << endl;
	cout << a / b << endl;
	cout << a % b << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值